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

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

Issue 11567031: [net/dns] Handle TC bit on DNS response in DnsTransaction. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: respond to review; added TCPMalformed test 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
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/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "base/rand_util.h" 18 #include "base/rand_util.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/string_piece.h" 20 #include "base/string_piece.h"
21 #include "base/threading/non_thread_safe.h" 21 #include "base/threading/non_thread_safe.h"
22 #include "base/timer.h" 22 #include "base/timer.h"
23 #include "base/values.h" 23 #include "base/values.h"
24 #include "net/base/big_endian.h"
24 #include "net/base/completion_callback.h" 25 #include "net/base/completion_callback.h"
25 #include "net/base/dns_util.h" 26 #include "net/base/dns_util.h"
26 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
27 #include "net/base/ip_endpoint.h" 28 #include "net/base/ip_endpoint.h"
28 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
29 #include "net/base/net_log.h" 30 #include "net/base/net_log.h"
30 #include "net/dns/dns_protocol.h" 31 #include "net/dns/dns_protocol.h"
31 #include "net/dns/dns_query.h" 32 #include "net/dns/dns_query.h"
32 #include "net/dns/dns_response.h" 33 #include "net/dns/dns_response.h"
33 #include "net/dns/dns_session.h" 34 #include "net/dns/dns_session.h"
35 #include "net/socket/stream_socket.h"
34 #include "net/udp/datagram_client_socket.h" 36 #include "net/udp/datagram_client_socket.h"
35 37
36 namespace net { 38 namespace net {
37 39
38 namespace { 40 namespace {
39 41
40 // Provide a common macro to simplify code and readability. We must use a 42 // Provide a common macro to simplify code and readability. We must use a
41 // macro as the underlying HISTOGRAM macro creates static variables. 43 // macro as the underlying HISTOGRAM macro creates static variables.
42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 44 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
43 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) 45 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
(...skipping 15 matching lines...) Expand all
59 uint16 qtype, 61 uint16 qtype,
60 NetLog::LogLevel /* log_level */) { 62 NetLog::LogLevel /* log_level */) {
61 DictionaryValue* dict = new DictionaryValue(); 63 DictionaryValue* dict = new DictionaryValue();
62 dict->SetString("hostname", *hostname); 64 dict->SetString("hostname", *hostname);
63 dict->SetInteger("query_type", qtype); 65 dict->SetInteger("query_type", qtype);
64 return dict; 66 return dict;
65 }; 67 };
66 68
67 // ---------------------------------------------------------------------------- 69 // ----------------------------------------------------------------------------
68 70
69 // A single asynchronous DNS exchange over UDP, which consists of sending out a 71 // A single asynchronous DNS exchange, which consists of sending out a
70 // DNS query, waiting for a response, and returning the response that it 72 // DNS query, waiting for a response, and returning the response that it
71 // matches. Logging is done in the socket and in the outer DnsTransaction. 73 // matches. Logging is done in the socket and in the outer DnsTransaction.
72 class DnsUDPAttempt { 74 class DnsAttempt {
75 public:
76 virtual ~DnsAttempt() {}
77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
78 // and calls |callback| upon completion.
79 virtual int Start(const CompletionCallback& callback) = 0;
80
81 // Returns the query of this attempt.
82 virtual const DnsQuery* GetQuery() const = 0;
83
84 // Returns the response or NULL if has not received a matching response from
85 // the server.
86 virtual const DnsResponse* GetResponse() const = 0;
87
88 // Returns the net log bound to the source of the socket.
89 virtual const BoundNetLog& GetSocketNetLog() const = 0;
90
91 // Returns the index of the destination server within DnsConfig::nameservers.
92 virtual unsigned GetServerIndex() const = 0;
93
94 // Returns a Value representing the received response, along with a reference
95 // to the NetLog source source of the UDP socket used. The request must have
96 // completed before this is called.
97 Value* NetLogResponseCallback(NetLog::LogLevel) const {
mmenke 2012/12/20 16:26:28 Per Google style guide: "Always have named parame
szym 2012/12/20 18:14:21 Done.
98 DCHECK(GetResponse()->IsValid());
99
100 DictionaryValue* dict = new DictionaryValue();
101 dict->SetInteger("rcode", GetResponse()->rcode());
102 dict->SetInteger("answer_count", GetResponse()->answer_count());
103 GetSocketNetLog().source().AddToEventParameters(dict);
104 return dict;
105 }
106 };
107
108 class DnsUDPAttempt : public DnsAttempt {
73 public: 109 public:
74 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, 110 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease,
75 scoped_ptr<DnsQuery> query, 111 scoped_ptr<DnsQuery> query)
76 const CompletionCallback& callback)
77 : next_state_(STATE_NONE), 112 : next_state_(STATE_NONE),
78 received_malformed_response_(false), 113 received_malformed_response_(false),
79 socket_lease_(socket_lease.Pass()), 114 socket_lease_(socket_lease.Pass()),
80 query_(query.Pass()), 115 query_(query.Pass()) {
81 callback_(callback) {
82 } 116 }
83 117
84 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 118 // DnsAttempt:
85 // and calls |callback| upon completion. 119 virtual int Start(const CompletionCallback& callback) OVERRIDE {
86 int Start() {
87 DCHECK_EQ(STATE_NONE, next_state_); 120 DCHECK_EQ(STATE_NONE, next_state_);
121 callback_ = callback;
88 start_time_ = base::TimeTicks::Now(); 122 start_time_ = base::TimeTicks::Now();
89 next_state_ = STATE_SEND_QUERY; 123 next_state_ = STATE_SEND_QUERY;
90 return DoLoop(OK); 124 return DoLoop(OK);
91 } 125 }
92 126
93 const DnsQuery* query() const { 127 virtual const DnsQuery* GetQuery() const OVERRIDE {
94 return query_.get(); 128 return query_.get();
95 } 129 }
96 130
97 const BoundNetLog& socket_net_log() const { 131 virtual const DnsResponse* GetResponse() const OVERRIDE {
98 return socket_lease_->socket()->NetLog();
99 }
100
101 // Returns the response or NULL if has not received a matching response from
102 // the server.
103 const DnsResponse* response() const {
104 const DnsResponse* resp = response_.get(); 132 const DnsResponse* resp = response_.get();
105 return (resp != NULL && resp->IsValid()) ? resp : NULL; 133 return (resp != NULL && resp->IsValid()) ? resp : NULL;
106 } 134 }
107 135
108 // Returns a Value representing the received response, along with a reference 136 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
109 // to the NetLog source source of the UDP socket used. The request must have 137 return socket_lease_->socket()->NetLog();
110 // completed before this is called. 138 }
111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
112 DCHECK(response_->IsValid());
113 139
114 DictionaryValue* dict = new DictionaryValue(); 140 virtual unsigned GetServerIndex() const OVERRIDE {
115 dict->SetInteger("rcode", response_->rcode()); 141 return socket_lease_->server_index();
116 dict->SetInteger("answer_count", response_->answer_count());
117 socket_net_log().source().AddToEventParameters(dict);
118 return dict;
119 } 142 }
120 143
121 private: 144 private:
122 enum State { 145 enum State {
123 STATE_SEND_QUERY, 146 STATE_SEND_QUERY,
124 STATE_SEND_QUERY_COMPLETE, 147 STATE_SEND_QUERY_COMPLETE,
125 STATE_READ_RESPONSE, 148 STATE_READ_RESPONSE,
126 STATE_READ_RESPONSE_COMPLETE, 149 STATE_READ_RESPONSE_COMPLETE,
127 STATE_NONE, 150 STATE_NONE,
128 }; 151 };
(...skipping 24 matching lines...) Expand all
153 default: 176 default:
154 NOTREACHED(); 177 NOTREACHED();
155 break; 178 break;
156 } 179 }
157 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 180 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
158 // If we received a malformed response, and are now waiting for another one, 181 // If we received a malformed response, and are now waiting for another one,
159 // indicate to the transaction that the server might be misbehaving. 182 // indicate to the transaction that the server might be misbehaving.
160 if (rv == ERR_IO_PENDING && received_malformed_response_) 183 if (rv == ERR_IO_PENDING && received_malformed_response_)
161 return ERR_DNS_MALFORMED_RESPONSE; 184 return ERR_DNS_MALFORMED_RESPONSE;
162 if (rv == OK) { 185 if (rv == OK) {
186 DCHECK_EQ(STATE_NONE, next_state_);
163 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess", 187 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
164 base::TimeTicks::Now() - start_time_); 188 base::TimeTicks::Now() - start_time_);
165 } else if (rv != ERR_IO_PENDING) { 189 } else if (rv != ERR_IO_PENDING) {
166 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", 190 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
167 base::TimeTicks::Now() - start_time_); 191 base::TimeTicks::Now() - start_time_);
168 } 192 }
169 return rv; 193 return rv;
170 } 194 }
171 195
172 int DoSendQuery() { 196 int DoSendQuery() {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 return OK; 240 return OK;
217 } 241 }
218 if (response_->flags() & dns_protocol::kFlagTC) 242 if (response_->flags() & dns_protocol::kFlagTC)
219 return ERR_DNS_SERVER_REQUIRES_TCP; 243 return ERR_DNS_SERVER_REQUIRES_TCP;
220 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 244 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
221 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 245 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
222 return ERR_NAME_NOT_RESOLVED; 246 return ERR_NAME_NOT_RESOLVED;
223 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 247 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
224 return ERR_DNS_SERVER_FAILED; 248 return ERR_DNS_SERVER_FAILED;
225 249
226 CHECK(response()); 250 CHECK(GetResponse());
mmenke 2012/12/20 16:26:28 Do we really need a CHECK here? Same goes for the
szym 2012/12/20 18:14:21 We don't. It's a left-over from trying to diagnose
227 return OK; 251 return OK;
228 } 252 }
229 253
230 void OnIOComplete(int rv) { 254 void OnIOComplete(int rv) {
231 rv = DoLoop(rv); 255 rv = DoLoop(rv);
232 if (rv != ERR_IO_PENDING) 256 if (rv != ERR_IO_PENDING)
233 callback_.Run(rv); 257 callback_.Run(rv);
234 } 258 }
235 259
236 State next_state_; 260 State next_state_;
237 bool received_malformed_response_; 261 bool received_malformed_response_;
238 base::TimeTicks start_time_; 262 base::TimeTicks start_time_;
239 263
240 scoped_ptr<DnsSession::SocketLease> socket_lease_; 264 scoped_ptr<DnsSession::SocketLease> socket_lease_;
241 scoped_ptr<DnsQuery> query_; 265 scoped_ptr<DnsQuery> query_;
242 266
243 scoped_ptr<DnsResponse> response_; 267 scoped_ptr<DnsResponse> response_;
244 268
245 CompletionCallback callback_; 269 CompletionCallback callback_;
246 270
247 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 271 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
248 }; 272 };
249 273
274 class DnsTCPAttempt : public DnsAttempt {
275 public:
276 DnsTCPAttempt(scoped_ptr<StreamSocket> socket,
277 scoped_ptr<DnsQuery> query)
278 : next_state_(STATE_NONE),
279 socket_(socket.Pass()),
280 query_(query.Pass()),
281 length_buffer_(new IOBufferWithSize(sizeof(uint16))),
282 response_length_(0) {
283 }
284
285 // DnsAttempt:
286 virtual int Start(const CompletionCallback& callback) OVERRIDE {
287 DCHECK_EQ(STATE_NONE, next_state_);
288 callback_ = callback;
289 start_time_ = base::TimeTicks::Now();
290 next_state_ = STATE_CONNECT_COMPLETE;
291 int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
292 base::Unretained(this)));
293 if (rv == ERR_IO_PENDING)
294 return rv;
295 return DoLoop(rv);
296 }
297
298 virtual const DnsQuery* GetQuery() const OVERRIDE {
299 return query_.get();
300 }
301
302 virtual const DnsResponse* GetResponse() const OVERRIDE {
303 const DnsResponse* resp = response_.get();
304 return (resp != NULL && resp->IsValid()) ? resp : NULL;
305 }
306
307 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
308 return socket_->NetLog();
309 }
310
311 virtual unsigned GetServerIndex() const OVERRIDE {
312 NOTREACHED();
313 return 0;
314 }
315
316 private:
317 enum State {
318 STATE_CONNECT_COMPLETE,
319 STATE_SEND_LENGTH,
320 STATE_SEND_QUERY,
321 STATE_READ_LENGTH,
322 STATE_READ_RESPONSE,
323 STATE_NONE,
324 };
325
326 int DoLoop(int result) {
327 CHECK_NE(STATE_NONE, next_state_);
328 int rv = result;
329 do {
330 State state = next_state_;
331 next_state_ = STATE_NONE;
332 switch (state) {
333 case STATE_CONNECT_COMPLETE:
334 rv = DoConnectComplete(rv);
335 break;
336 case STATE_SEND_LENGTH:
337 rv = DoSendLength(rv);
338 break;
339 case STATE_SEND_QUERY:
340 rv = DoSendQuery(rv);
341 break;
342 case STATE_READ_LENGTH:
343 rv = DoReadLength(rv);
344 break;
345 case STATE_READ_RESPONSE:
346 rv = DoReadResponse(rv);
347 break;
348 default:
349 NOTREACHED();
350 break;
351 }
352 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
353 if (rv == OK) {
354 DCHECK_EQ(STATE_NONE, next_state_);
355 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
356 base::TimeTicks::Now() - start_time_);
357 } else if (rv != ERR_IO_PENDING) {
358 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
359 base::TimeTicks::Now() - start_time_);
360 }
361 return rv;
362 }
363
364 int DoConnectComplete(int rv) {
365 DCHECK_NE(ERR_IO_PENDING, rv);
366 if (rv < 0)
367 return rv;
368
369 WriteBigEndian<uint16>(length_buffer_->data(), query_->io_buffer()->size());
370 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
371 next_state_ = STATE_SEND_LENGTH;
372 return OK;
373 }
374
375 int DoSendLength(int rv) {
376 DCHECK_NE(ERR_IO_PENDING, rv);
377 if (rv < 0)
378 return rv;
379
380 buffer_->DidConsume(rv);
381 if (buffer_->BytesRemaining() > 0) {
382 next_state_ = STATE_SEND_LENGTH;
383 return socket_->Write(buffer_,
384 buffer_->BytesRemaining(),
385 base::Bind(&DnsTCPAttempt::OnIOComplete,
386 base::Unretained(this)));
387 }
388 buffer_ = new DrainableIOBuffer(query_->io_buffer(),
389 query_->io_buffer()->size());
390 next_state_ = STATE_SEND_QUERY;
391 return OK;
392 }
393
394 int DoSendQuery(int rv) {
395 DCHECK_NE(ERR_IO_PENDING, rv);
396 if (rv < 0)
397 return rv;
398
399 buffer_->DidConsume(rv);
400 if (buffer_->BytesRemaining() > 0) {
401 next_state_ = STATE_SEND_QUERY;
402 return socket_->Write(buffer_,
403 buffer_->BytesRemaining(),
404 base::Bind(&DnsTCPAttempt::OnIOComplete,
405 base::Unretained(this)));
406 }
407 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
408 next_state_ = STATE_READ_LENGTH;
409 return OK;
410 }
411
412 int DoReadLength(int rv) {
413 DCHECK_NE(ERR_IO_PENDING, rv);
414 if (rv < 0)
415 return rv;
416
417 buffer_->DidConsume(rv);
418 if (buffer_->BytesRemaining() > 0) {
419 next_state_ = STATE_READ_LENGTH;
420 return socket_->Read(buffer_,
421 buffer_->BytesRemaining(),
422 base::Bind(&DnsTCPAttempt::OnIOComplete,
423 base::Unretained(this)));
424 }
425 ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
426 // Check if advertised response is too short. (Optimization only.)
szym 2012/12/19 23:35:57 This comment is meant to reflect that if we remove
427 if (response_length_ < query_->io_buffer()->size())
428 return ERR_DNS_MALFORMED_RESPONSE;
429 // Allocate more space so that DnsResponse::InitParse sanity check passes.
430 response_.reset(new DnsResponse(response_length_ + 1));
431 buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
432 next_state_ = STATE_READ_RESPONSE;
433 return OK;
434 }
435
436 int DoReadResponse(int rv) {
437 DCHECK_NE(ERR_IO_PENDING, rv);
438 if (rv < 0)
439 return rv;
440
441 buffer_->DidConsume(rv);
442 if (buffer_->BytesRemaining() > 0) {
443 next_state_ = STATE_READ_RESPONSE;
444 return socket_->Read(buffer_,
445 buffer_->BytesRemaining(),
446 base::Bind(&DnsTCPAttempt::OnIOComplete,
447 base::Unretained(this)));
448 }
449 if (!response_->InitParse(buffer_->BytesConsumed(), *query_)) {
450 return ERR_DNS_MALFORMED_RESPONSE;
451 }
452 if (response_->flags() & dns_protocol::kFlagTC)
453 return ERR_UNEXPECTED;
454 // TODO(szym): Frankly, none of these are expected.
455 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
456 return ERR_NAME_NOT_RESOLVED;
457 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
458 return ERR_DNS_SERVER_FAILED;
459
460 CHECK(GetResponse());
461 return OK;
462 }
463
464 void OnIOComplete(int rv) {
465 rv = DoLoop(rv);
466 if (rv != ERR_IO_PENDING)
467 callback_.Run(rv);
468 }
469
470 State next_state_;
471 base::TimeTicks start_time_;
472
473 scoped_ptr<StreamSocket> socket_;
474 scoped_ptr<DnsQuery> query_;
475 scoped_refptr<IOBufferWithSize> length_buffer_;
476 scoped_refptr<DrainableIOBuffer> buffer_;
477
478 uint16 response_length_;
479 scoped_ptr<DnsResponse> response_;
480
481 CompletionCallback callback_;
482
483 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
484 };
485
250 // ---------------------------------------------------------------------------- 486 // ----------------------------------------------------------------------------
251 487
252 // Implements DnsTransaction. Configuration is supplied by DnsSession. 488 // Implements DnsTransaction. Configuration is supplied by DnsSession.
253 // The suffix list is built according to the DnsConfig from the session. 489 // The suffix list is built according to the DnsConfig from the session.
254 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. 490 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
255 // The first server to attempt on each query is given by 491 // The first server to attempt on each query is given by
256 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. 492 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
257 // Each server is attempted DnsConfig::attempts times. 493 // Each server is attempted DnsConfig::attempts times.
258 class DnsTransactionImpl : public DnsTransaction, 494 class DnsTransactionImpl : public DnsTransaction,
259 public base::NonThreadSafe, 495 public base::NonThreadSafe,
260 public base::SupportsWeakPtr<DnsTransactionImpl> { 496 public base::SupportsWeakPtr<DnsTransactionImpl> {
261 public: 497 public:
262 DnsTransactionImpl(DnsSession* session, 498 DnsTransactionImpl(DnsSession* session,
263 const std::string& hostname, 499 const std::string& hostname,
264 uint16 qtype, 500 uint16 qtype,
265 const DnsTransactionFactory::CallbackType& callback, 501 const DnsTransactionFactory::CallbackType& callback,
266 const BoundNetLog& net_log) 502 const BoundNetLog& net_log)
267 : session_(session), 503 : session_(session),
268 hostname_(hostname), 504 hostname_(hostname),
269 qtype_(qtype), 505 qtype_(qtype),
270 callback_(callback), 506 callback_(callback),
271 net_log_(net_log), 507 net_log_(net_log),
508 had_tcp_attempt_(false),
272 first_server_index_(0) { 509 first_server_index_(0) {
273 DCHECK(session_); 510 DCHECK(session_);
274 DCHECK(!hostname_.empty()); 511 DCHECK(!hostname_.empty());
275 DCHECK(!callback_.is_null()); 512 DCHECK(!callback_.is_null());
276 DCHECK(!IsIPLiteral(hostname_)); 513 DCHECK(!IsIPLiteral(hostname_));
277 } 514 }
278 515
279 virtual ~DnsTransactionImpl() { 516 virtual ~DnsTransactionImpl() {
280 if (!callback_.is_null()) { 517 if (!callback_.is_null()) {
281 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 518 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 callback_.Reset(); 551 callback_.Reset();
315 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv); 552 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv);
316 } 553 }
317 DCHECK_NE(OK, rv); 554 DCHECK_NE(OK, rv);
318 return rv; 555 return rv;
319 } 556 }
320 557
321 private: 558 private:
322 // Wrapper for the result of a DnsUDPAttempt. 559 // Wrapper for the result of a DnsUDPAttempt.
323 struct AttemptResult { 560 struct AttemptResult {
324 AttemptResult(int rv, const DnsUDPAttempt* attempt) 561 AttemptResult(int rv, const DnsAttempt* attempt)
325 : rv(rv), attempt(attempt) {} 562 : rv(rv), attempt(attempt) {}
326 563
327 int rv; 564 int rv;
328 const DnsUDPAttempt* attempt; 565 const DnsAttempt* attempt;
329 }; 566 };
330 567
331 // Prepares |qnames_| according to the DnsConfig. 568 // Prepares |qnames_| according to the DnsConfig.
332 int PrepareSearch() { 569 int PrepareSearch() {
333 const DnsConfig& config = session_->config(); 570 const DnsConfig& config = session_->config();
334 571
335 std::string labeled_hostname; 572 std::string labeled_hostname;
336 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 573 if (!DNSDomainFromDot(hostname_, &labeled_hostname))
337 return ERR_INVALID_ARGUMENT; 574 return ERR_INVALID_ARGUMENT;
338 575
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 if (ndots > 0 && !had_hostname) 610 if (ndots > 0 && !had_hostname)
374 qnames_.push_back(labeled_hostname); 611 qnames_.push_back(labeled_hostname);
375 612
376 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK; 613 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
377 } 614 }
378 615
379 void DoCallback(AttemptResult result) { 616 void DoCallback(AttemptResult result) {
380 DCHECK(!callback_.is_null()); 617 DCHECK(!callback_.is_null());
381 DCHECK_NE(ERR_IO_PENDING, result.rv); 618 DCHECK_NE(ERR_IO_PENDING, result.rv);
382 const DnsResponse* response = result.attempt ? 619 const DnsResponse* response = result.attempt ?
383 result.attempt->response() : NULL; 620 result.attempt->GetResponse() : NULL;
384 CHECK(result.rv != OK || response != NULL); 621 CHECK(result.rv != OK || response != NULL);
385 622
386 timer_.Stop(); 623 timer_.Stop();
387 624
388 DnsTransactionFactory::CallbackType callback = callback_; 625 DnsTransactionFactory::CallbackType callback = callback_;
389 callback_.Reset(); 626 callback_.Reset();
390 627
391 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 628 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
392 callback.Run(this, result.rv, response); 629 callback.Run(this, result.rv, response);
393 } 630 }
394 631
395 // Makes another attempt at the current name, |qnames_.front()|, using the 632 // Makes another attempt at the current name, |qnames_.front()|, using the
396 // next nameserver. 633 // next nameserver.
397 AttemptResult MakeAttempt() { 634 AttemptResult MakeAttempt() {
398 unsigned attempt_number = attempts_.size(); 635 unsigned attempt_number = attempts_.size();
399 636
400 uint16 id = session_->NextQueryId(); 637 uint16 id = session_->NextQueryId();
401 scoped_ptr<DnsQuery> query; 638 scoped_ptr<DnsQuery> query;
402 if (attempts_.empty()) { 639 if (attempts_.empty()) {
403 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 640 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
404 } else { 641 } else {
405 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 642 query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
406 } 643 }
407 644
408 const DnsConfig& config = session_->config(); 645 const DnsConfig& config = session_->config();
409 646
410 unsigned server_index = first_server_index_ + 647 unsigned server_index = first_server_index_ +
411 (attempt_number % config.nameservers.size()); 648 (attempt_number % config.nameservers.size());
412 649
413 scoped_ptr<DnsSession::SocketLease> lease = 650 scoped_ptr<DnsSession::SocketLease> lease =
414 session_->AllocateSocket(server_index, net_log_.source()); 651 session_->AllocateSocket(server_index, net_log_.source());
415 652
416 bool got_socket = !!lease.get(); 653 bool got_socket = !!lease.get();
417 654
418 DnsUDPAttempt* attempt = new DnsUDPAttempt( 655 DnsUDPAttempt* attempt = new DnsUDPAttempt(lease.Pass(), query.Pass());
419 lease.Pass(),
420 query.Pass(),
421 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
422 base::Unretained(this),
423 attempt_number));
424 656
425 attempts_.push_back(attempt); 657 attempts_.push_back(attempt);
426 658
427 if (!got_socket) 659 if (!got_socket)
428 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 660 return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
429 661
430 net_log_.AddEvent( 662 net_log_.AddEvent(
431 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 663 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
432 attempt->socket_net_log().source().ToEventParametersCallback()); 664 attempt->GetSocketNetLog().source().ToEventParametersCallback());
433 665
434 int rv = attempt->Start(); 666 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
667 base::Unretained(this),
668 attempt_number));
435 if (rv == ERR_IO_PENDING) { 669 if (rv == ERR_IO_PENDING) {
436 timer_.Stop();
437 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 670 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
438 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 671 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
439 } 672 }
440 return AttemptResult(rv, attempt); 673 return AttemptResult(rv, attempt);
441 } 674 }
442 675
676 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
677 DCHECK(previous_attempt);
678 DCHECK(!had_tcp_attempt_);
679
680 scoped_ptr<StreamSocket> socket(
681 session_->CreateTCPSocket(previous_attempt->GetServerIndex(),
682 net_log_.source()));
683
684 // TODO(szym): Reuse the same id to help the server?
685 uint16 id = session_->NextQueryId();
686 scoped_ptr<DnsQuery> query(
687 previous_attempt->GetQuery()->CloneWithNewId(id));
688
689 // Cancel all other attempts, no point waiting on them.
690 attempts_.clear();
691
692 unsigned attempt_number = attempts_.size();
693
694 DnsTCPAttempt* attempt = new DnsTCPAttempt(socket.Pass(), query.Pass());
695
696 attempts_.push_back(attempt);
697 had_tcp_attempt_ = true;
698
699 net_log_.AddEvent(
700 NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
701 attempt->GetSocketNetLog().source().ToEventParametersCallback());
702
703 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
704 base::Unretained(this),
705 attempt_number));
706 if (rv == ERR_IO_PENDING) {
707 // Custom timeout for TCP attempt.
708 base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
709 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
710 }
711 return AttemptResult(rv, attempt);
712 }
713
443 // Begins query for the current name. Makes the first attempt. 714 // Begins query for the current name. Makes the first attempt.
444 AttemptResult StartQuery() { 715 AttemptResult StartQuery() {
445 std::string dotted_qname = DNSDomainToString(qnames_.front()); 716 std::string dotted_qname = DNSDomainToString(qnames_.front());
446 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY, 717 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
447 NetLog::StringCallback("qname", &dotted_qname)); 718 NetLog::StringCallback("qname", &dotted_qname));
448 719
449 first_server_index_ = session_->NextFirstServerIndex(); 720 first_server_index_ = session_->NextFirstServerIndex();
450 721
451 attempts_.clear(); 722 attempts_.clear();
723 had_tcp_attempt_ = false;
452 return MakeAttempt(); 724 return MakeAttempt();
453 } 725 }
454 726
455 void OnAttemptComplete(unsigned attempt_number, int rv) { 727 void OnAttemptComplete(unsigned attempt_number, int rv) {
456 if (callback_.is_null()) 728 if (callback_.is_null())
457 return; 729 return;
458 DCHECK_LT(attempt_number, attempts_.size()); 730 DCHECK_LT(attempt_number, attempts_.size());
459 const DnsUDPAttempt* attempt = attempts_[attempt_number]; 731 const DnsAttempt* attempt = attempts_[attempt_number];
460 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt)); 732 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
461 if (result.rv != ERR_IO_PENDING) 733 if (result.rv != ERR_IO_PENDING)
462 DoCallback(result); 734 DoCallback(result);
463 } 735 }
464 736
465 void LogResponse(const DnsUDPAttempt* attempt) { 737 void LogResponse(const DnsAttempt* attempt) {
466 if (attempt && attempt->response()) { 738 if (attempt && attempt->GetResponse()) {
467 net_log_.AddEvent( 739 net_log_.AddEvent(
468 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 740 NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
469 base::Bind(&DnsUDPAttempt::NetLogResponseCallback, 741 base::Bind(&DnsAttempt::NetLogResponseCallback,
470 base::Unretained(attempt))); 742 base::Unretained(attempt)));
471 } 743 }
472 } 744 }
473 745
474 bool MoreAttemptsAllowed() const { 746 bool MoreAttemptsAllowed() const {
747 if (had_tcp_attempt_)
748 return false;
475 const DnsConfig& config = session_->config(); 749 const DnsConfig& config = session_->config();
476 return attempts_.size() < config.attempts * config.nameservers.size(); 750 return attempts_.size() < config.attempts * config.nameservers.size();
477 } 751 }
478 752
479 // Resolves the result of a DnsUDPAttempt until a terminal result is reached 753 // Resolves the result of a DnsAttempt until a terminal result is reached
480 // or it will complete asynchronously (ERR_IO_PENDING). 754 // or it will complete asynchronously (ERR_IO_PENDING).
481 AttemptResult ProcessAttemptResult(AttemptResult result) { 755 AttemptResult ProcessAttemptResult(AttemptResult result) {
482 while (result.rv != ERR_IO_PENDING) { 756 while (result.rv != ERR_IO_PENDING) {
483 LogResponse(result.attempt); 757 LogResponse(result.attempt);
484 758
485 switch (result.rv) { 759 switch (result.rv) {
486 case OK: 760 case OK:
487 net_log_.EndEventWithNetErrorCode( 761 net_log_.EndEventWithNetErrorCode(
488 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 762 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
489 DCHECK(result.attempt); 763 DCHECK(result.attempt);
490 DCHECK(result.attempt->response()); 764 DCHECK(result.attempt->GetResponse());
491 return result; 765 return result;
492 case ERR_NAME_NOT_RESOLVED: 766 case ERR_NAME_NOT_RESOLVED:
493 net_log_.EndEventWithNetErrorCode( 767 net_log_.EndEventWithNetErrorCode(
494 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 768 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
495 // Try next suffix. 769 // Try next suffix.
496 qnames_.pop_front(); 770 qnames_.pop_front();
497 if (qnames_.empty()) { 771 if (qnames_.empty()) {
498 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 772 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
499 } else { 773 } else {
500 result = StartQuery(); 774 result = StartQuery();
501 } 775 }
502 break; 776 break;
503 case ERR_CONNECTION_REFUSED: 777 case ERR_CONNECTION_REFUSED:
504 case ERR_DNS_TIMED_OUT: 778 case ERR_DNS_TIMED_OUT:
505 if (MoreAttemptsAllowed()) { 779 if (MoreAttemptsAllowed()) {
506 result = MakeAttempt(); 780 result = MakeAttempt();
507 } else { 781 } else {
508 return result; 782 return result;
509 } 783 }
510 break; 784 break;
785 case ERR_DNS_SERVER_REQUIRES_TCP:
786 result = MakeTCPAttempt(result.attempt);
787 break;
511 default: 788 default:
512 // Server failure. 789 // Server failure.
513 DCHECK(result.attempt); 790 DCHECK(result.attempt);
514 if (result.attempt != attempts_.back()) { 791 if (result.attempt != attempts_.back()) {
515 // This attempt already timed out. Ignore it. 792 // This attempt already timed out. Ignore it.
516 return AttemptResult(ERR_IO_PENDING, NULL); 793 return AttemptResult(ERR_IO_PENDING, NULL);
517 } 794 }
518 if (MoreAttemptsAllowed()) { 795 if (MoreAttemptsAllowed()) {
519 result = MakeAttempt(); 796 result = MakeAttempt();
520 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE) { 797 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
798 !had_tcp_attempt_) {
szym 2012/12/19 23:35:57 PTAL. Logic change.
mmenke 2012/12/20 16:26:28 Nice catch. Think this is worth a short comment a
szym 2012/12/20 18:14:21 Done.
521 // Wait until the last attempt times out. 799 // Wait until the last attempt times out.
522 return AttemptResult(ERR_IO_PENDING, NULL); 800 return AttemptResult(ERR_IO_PENDING, NULL);
523 } else { 801 } else {
524 return AttemptResult(result.rv, NULL); 802 return AttemptResult(result.rv, NULL);
525 } 803 }
526 break; 804 break;
527 } 805 }
528 } 806 }
529 return result; 807 return result;
530 } 808 }
(...skipping 12 matching lines...) Expand all
543 uint16 qtype_; 821 uint16 qtype_;
544 // Cleared in DoCallback. 822 // Cleared in DoCallback.
545 DnsTransactionFactory::CallbackType callback_; 823 DnsTransactionFactory::CallbackType callback_;
546 824
547 BoundNetLog net_log_; 825 BoundNetLog net_log_;
548 826
549 // Search list of fully-qualified DNS names to query next (in DNS format). 827 // Search list of fully-qualified DNS names to query next (in DNS format).
550 std::deque<std::string> qnames_; 828 std::deque<std::string> qnames_;
551 829
552 // List of attempts for the current name. 830 // List of attempts for the current name.
553 ScopedVector<DnsUDPAttempt> attempts_; 831 ScopedVector<DnsAttempt> attempts_;
832 bool had_tcp_attempt_;
554 833
555 // Index of the first server to try on each search query. 834 // Index of the first server to try on each search query.
556 int first_server_index_; 835 int first_server_index_;
557 836
558 base::OneShotTimer<DnsTransactionImpl> timer_; 837 base::OneShotTimer<DnsTransactionImpl> timer_;
559 838
560 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 839 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
561 }; 840 };
562 841
563 // ---------------------------------------------------------------------------- 842 // ----------------------------------------------------------------------------
(...skipping 25 matching lines...) Expand all
589 } // namespace 868 } // namespace
590 869
591 // static 870 // static
592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 871 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
593 DnsSession* session) { 872 DnsSession* session) {
594 return scoped_ptr<DnsTransactionFactory>( 873 return scoped_ptr<DnsTransactionFactory>(
595 new DnsTransactionFactoryImpl(session)); 874 new DnsTransactionFactoryImpl(session));
596 } 875 }
597 876
598 } // namespace net 877 } // 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