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

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

Issue 10824238: [net/dns] Don't abandon a DnsUDPAttempt when the response does not match the query. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync Created 8 years, 3 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 | « no previous file | 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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 // A single asynchronous DNS exchange over UDP, which consists of sending out a 64 // 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 65 // 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. 66 // matches. Logging is done in the socket and in the outer DnsTransaction.
67 class DnsUDPAttempt { 67 class DnsUDPAttempt {
68 public: 68 public:
69 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, 69 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket,
70 const IPEndPoint& server, 70 const IPEndPoint& server,
71 scoped_ptr<DnsQuery> query, 71 scoped_ptr<DnsQuery> query,
72 const CompletionCallback& callback) 72 const CompletionCallback& callback)
73 : next_state_(STATE_NONE), 73 : next_state_(STATE_NONE),
74 received_malformed_response_(false),
74 socket_(socket.Pass()), 75 socket_(socket.Pass()),
75 server_(server), 76 server_(server),
76 query_(query.Pass()), 77 query_(query.Pass()),
77 callback_(callback) { 78 callback_(callback) {
78 } 79 }
79 80
80 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 81 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
81 // and calls |callback| upon completion. 82 // and calls |callback| upon completion.
82 int Start() { 83 int Start() {
83 DCHECK_EQ(STATE_NONE, next_state_); 84 DCHECK_EQ(STATE_NONE, next_state_);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 rv = DoReadResponse(); 144 rv = DoReadResponse();
144 break; 145 break;
145 case STATE_READ_RESPONSE_COMPLETE: 146 case STATE_READ_RESPONSE_COMPLETE:
146 rv = DoReadResponseComplete(rv); 147 rv = DoReadResponseComplete(rv);
147 break; 148 break;
148 default: 149 default:
149 NOTREACHED(); 150 NOTREACHED();
150 break; 151 break;
151 } 152 }
152 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 153 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
153 154 // If we received a malformed response, and are now waiting for another one,
155 // indicate to the transaction that the server might be misbehaving.
156 if (rv == ERR_IO_PENDING && received_malformed_response_)
157 return ERR_DNS_MALFORMED_RESPONSE;
154 return rv; 158 return rv;
155 } 159 }
156 160
157 int DoConnect() { 161 int DoConnect() {
158 next_state_ = STATE_SEND_QUERY; 162 next_state_ = STATE_SEND_QUERY;
159 return socket_->Connect(server_); 163 return socket_->Connect(server_);
160 } 164 }
161 165
162 int DoSendQuery() { 166 int DoSendQuery() {
163 next_state_ = STATE_SEND_QUERY_COMPLETE; 167 next_state_ = STATE_SEND_QUERY_COMPLETE;
(...skipping 25 matching lines...) Expand all
189 base::Unretained(this))); 193 base::Unretained(this)));
190 } 194 }
191 195
192 int DoReadResponseComplete(int rv) { 196 int DoReadResponseComplete(int rv) {
193 DCHECK_NE(ERR_IO_PENDING, rv); 197 DCHECK_NE(ERR_IO_PENDING, rv);
194 if (rv < 0) 198 if (rv < 0)
195 return rv; 199 return rv;
196 200
197 DCHECK(rv); 201 DCHECK(rv);
198 if (!response_->InitParse(rv, *query_)) { 202 if (!response_->InitParse(rv, *query_)) {
199 // TODO(szym): Consider making this reaction less aggressive.
200 // Other implementations simply ignore mismatched responses. Since each 203 // Other implementations simply ignore mismatched responses. Since each
201 // DnsUDPAttempt binds to a different port, we might find that responses 204 // DnsUDPAttempt binds to a different port, we might find that responses
202 // to previously timed out queries lead to failures in the future. 205 // to previously timed out queries lead to failures in the future.
203 // http://crbug.com/107413 206 // Our solution is to make another attempt, in case the query truly
204 return ERR_DNS_MALFORMED_RESPONSE; 207 // failed, but keep this attempt alive, in case it was a false alarm.
208 received_malformed_response_ = true;
209 next_state_ = STATE_READ_RESPONSE;
210 return OK;
205 } 211 }
206 if (response_->flags() & dns_protocol::kFlagTC) 212 if (response_->flags() & dns_protocol::kFlagTC)
207 return ERR_DNS_SERVER_REQUIRES_TCP; 213 return ERR_DNS_SERVER_REQUIRES_TCP;
208 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 214 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
209 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 215 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
210 return ERR_NAME_NOT_RESOLVED; 216 return ERR_NAME_NOT_RESOLVED;
211 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 217 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
212 return ERR_DNS_SERVER_FAILED; 218 return ERR_DNS_SERVER_FAILED;
213 219
214 CHECK(response()); 220 CHECK(response());
215 return OK; 221 return OK;
216 } 222 }
217 223
218 void OnIOComplete(int rv) { 224 void OnIOComplete(int rv) {
219 rv = DoLoop(rv); 225 rv = DoLoop(rv);
220 if (rv != ERR_IO_PENDING) 226 if (rv != ERR_IO_PENDING)
221 callback_.Run(rv); 227 callback_.Run(rv);
222 } 228 }
223 229
224 State next_state_; 230 State next_state_;
231 bool received_malformed_response_;
225 232
226 scoped_ptr<DatagramClientSocket> socket_; 233 scoped_ptr<DatagramClientSocket> socket_;
227 IPEndPoint server_; 234 IPEndPoint server_;
228 scoped_ptr<DnsQuery> query_; 235 scoped_ptr<DnsQuery> query_;
229 236
230 scoped_ptr<DnsResponse> response_; 237 scoped_ptr<DnsResponse> response_;
231 238
232 CompletionCallback callback_; 239 CompletionCallback callback_;
233 240
234 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 241 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 return qtype_; 287 return qtype_;
281 } 288 }
282 289
283 virtual int Start() OVERRIDE { 290 virtual int Start() OVERRIDE {
284 DCHECK(!callback_.is_null()); 291 DCHECK(!callback_.is_null());
285 DCHECK(attempts_.empty()); 292 DCHECK(attempts_.empty());
286 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, 293 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
287 base::Bind(&NetLogStartCallback, &hostname_, qtype_)); 294 base::Bind(&NetLogStartCallback, &hostname_, qtype_));
288 int rv = PrepareSearch(); 295 int rv = PrepareSearch();
289 if (rv == OK) { 296 if (rv == OK) {
290 AttemptResult result = FinishAttempt(StartQuery()); 297 AttemptResult result = ProcessAttemptResult(StartQuery());
291 if (result.rv == OK) { 298 if (result.rv == OK) {
292 // DnsTransaction must never succeed synchronously. 299 // DnsTransaction must never succeed synchronously.
293 MessageLoop::current()->PostTask( 300 MessageLoop::current()->PostTask(
294 FROM_HERE, 301 FROM_HERE,
295 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result)); 302 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
296 return ERR_IO_PENDING; 303 return ERR_IO_PENDING;
297 } 304 }
298 rv = result.rv; 305 rv = result.rv;
299 } 306 }
300 if (rv != ERR_IO_PENDING) { 307 if (rv != ERR_IO_PENDING) {
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 451
445 attempts_.clear(); 452 attempts_.clear();
446 return MakeAttempt(); 453 return MakeAttempt();
447 } 454 }
448 455
449 void OnAttemptComplete(unsigned attempt_number, int rv) { 456 void OnAttemptComplete(unsigned attempt_number, int rv) {
450 if (callback_.is_null()) 457 if (callback_.is_null())
451 return; 458 return;
452 DCHECK_LT(attempt_number, attempts_.size()); 459 DCHECK_LT(attempt_number, attempts_.size());
453 const DnsUDPAttempt* attempt = attempts_[attempt_number]; 460 const DnsUDPAttempt* attempt = attempts_[attempt_number];
454 AttemptResult result = FinishAttempt(AttemptResult(rv, attempt)); 461 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
455 if (result.rv != ERR_IO_PENDING) 462 if (result.rv != ERR_IO_PENDING)
456 DoCallback(result); 463 DoCallback(result);
457 } 464 }
458 465
459 void LogResponse(const DnsUDPAttempt* attempt) { 466 void LogResponse(const DnsUDPAttempt* attempt) {
460 if (attempt && attempt->response()) { 467 if (attempt && attempt->response()) {
461 net_log_.AddEvent( 468 net_log_.AddEvent(
462 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 469 NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
463 base::Bind(&DnsUDPAttempt::NetLogResponseCallback, 470 base::Bind(&DnsUDPAttempt::NetLogResponseCallback,
464 base::Unretained(attempt))); 471 base::Unretained(attempt)));
465 } 472 }
466 } 473 }
467 474
468 bool MoreAttemptsAllowed() const { 475 bool MoreAttemptsAllowed() const {
469 const DnsConfig& config = session_->config(); 476 const DnsConfig& config = session_->config();
470 return attempts_.size() < config.attempts * config.nameservers.size(); 477 return attempts_.size() < config.attempts * config.nameservers.size();
471 } 478 }
472 479
473 // Resolves the result of a DnsUDPAttempt until a terminal result is reached 480 // Resolves the result of a DnsUDPAttempt until a terminal result is reached
474 // or it will complete asynchronously (ERR_IO_PENDING). 481 // or it will complete asynchronously (ERR_IO_PENDING).
475 AttemptResult FinishAttempt(AttemptResult result) { 482 AttemptResult ProcessAttemptResult(AttemptResult result) {
476 while (result.rv != ERR_IO_PENDING) { 483 while (result.rv != ERR_IO_PENDING) {
477 LogResponse(result.attempt); 484 LogResponse(result.attempt);
478 485
479 switch (result.rv) { 486 switch (result.rv) {
480 case OK: 487 case OK:
481 net_log_.EndEventWithNetErrorCode( 488 net_log_.EndEventWithNetErrorCode(
482 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 489 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
483 DCHECK(result.attempt); 490 DCHECK(result.attempt);
484 DCHECK(result.attempt->response()); 491 DCHECK(result.attempt->response());
485 return result; 492 return result;
(...skipping 17 matching lines...) Expand all
503 break; 510 break;
504 default: 511 default:
505 // Server failure. 512 // Server failure.
506 DCHECK(result.attempt); 513 DCHECK(result.attempt);
507 if (result.attempt != attempts_.back()) { 514 if (result.attempt != attempts_.back()) {
508 // This attempt already timed out. Ignore it. 515 // This attempt already timed out. Ignore it.
509 return AttemptResult(ERR_IO_PENDING, NULL); 516 return AttemptResult(ERR_IO_PENDING, NULL);
510 } 517 }
511 if (MoreAttemptsAllowed()) { 518 if (MoreAttemptsAllowed()) {
512 result = MakeAttempt(); 519 result = MakeAttempt();
520 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE) {
521 // Wait until the last attempt times out.
522 return AttemptResult(ERR_IO_PENDING, NULL);
513 } else { 523 } else {
514 return AttemptResult(result.rv, NULL); 524 return AttemptResult(result.rv, NULL);
515 } 525 }
516 break; 526 break;
517 } 527 }
518 } 528 }
519 return result; 529 return result;
520 } 530 }
521 531
522 void OnTimeout() { 532 void OnTimeout() {
523 if (callback_.is_null()) 533 if (callback_.is_null())
524 return; 534 return;
525 AttemptResult result = FinishAttempt( 535 AttemptResult result = ProcessAttemptResult(
526 AttemptResult(ERR_DNS_TIMED_OUT, NULL)); 536 AttemptResult(ERR_DNS_TIMED_OUT, NULL));
527 if (result.rv != ERR_IO_PENDING) 537 if (result.rv != ERR_IO_PENDING)
528 DoCallback(result); 538 DoCallback(result);
529 } 539 }
530 540
531 scoped_refptr<DnsSession> session_; 541 scoped_refptr<DnsSession> session_;
532 std::string hostname_; 542 std::string hostname_;
533 uint16 qtype_; 543 uint16 qtype_;
534 // Cleared in DoCallback. 544 // Cleared in DoCallback.
535 DnsTransactionFactory::CallbackType callback_; 545 DnsTransactionFactory::CallbackType callback_;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 } // namespace 589 } // namespace
580 590
581 // static 591 // static
582 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
583 DnsSession* session) { 593 DnsSession* session) {
584 return scoped_ptr<DnsTransactionFactory>( 594 return scoped_ptr<DnsTransactionFactory>(
585 new DnsTransactionFactoryImpl(session)); 595 new DnsTransactionFactoryImpl(session));
586 } 596 }
587 597
588 } // namespace net 598 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698