Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 // Indicate to the transaction that the server might be misbehaving. |
| 155 if (rv == ERR_IO_PENDING && received_malformed_response_) | |
| 156 return ERR_DNS_MALFORMED_RESPONSE; | |
|
mmenke
2012/08/29 16:23:57
When does this happen? Won't we just end up with
szym
2012/08/29 21:37:26
As long as we have packets on the socket, we will
mmenke
2012/08/29 21:43:53
I'm not following. It seems to me like this if st
mmenke
2012/08/29 21:46:42
Err...That should be "that if statement will never
szym
2012/08/29 21:55:05
The goal is not to just ignore malformed packets b
mmenke
2012/08/29 22:01:22
But DoReadResponse sets next_state_ to STATE_READ_
szym
2012/08/29 22:19:11
If DoReadResponse returns ERR_IO_PENDING, then we
mmenke
2012/08/29 22:29:44
Gah, for some reason, I was thinking the next_stat
szym
2012/08/29 22:33:41
Note that the attempt will be kept alive and that
| |
| 157 // If we received any other result, it takes precedence. | |
| 158 received_malformed_response_ = false; | |
|
szym
2012/08/29 21:37:26
On second thought, this is not necessary. At that
| |
| 154 return rv; | 159 return rv; |
| 155 } | 160 } |
| 156 | 161 |
| 157 int DoConnect() { | 162 int DoConnect() { |
| 158 next_state_ = STATE_SEND_QUERY; | 163 next_state_ = STATE_SEND_QUERY; |
| 159 return socket_->Connect(server_); | 164 return socket_->Connect(server_); |
| 160 } | 165 } |
| 161 | 166 |
| 162 int DoSendQuery() { | 167 int DoSendQuery() { |
| 163 next_state_ = STATE_SEND_QUERY_COMPLETE; | 168 next_state_ = STATE_SEND_QUERY_COMPLETE; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 189 base::Unretained(this))); | 194 base::Unretained(this))); |
| 190 } | 195 } |
| 191 | 196 |
| 192 int DoReadResponseComplete(int rv) { | 197 int DoReadResponseComplete(int rv) { |
| 193 DCHECK_NE(ERR_IO_PENDING, rv); | 198 DCHECK_NE(ERR_IO_PENDING, rv); |
| 194 if (rv < 0) | 199 if (rv < 0) |
| 195 return rv; | 200 return rv; |
| 196 | 201 |
| 197 DCHECK(rv); | 202 DCHECK(rv); |
| 198 if (!response_->InitParse(rv, *query_)) { | 203 if (!response_->InitParse(rv, *query_)) { |
| 199 // TODO(szym): Consider making this reaction less aggressive. | |
| 200 // Other implementations simply ignore mismatched responses. Since each | 204 // Other implementations simply ignore mismatched responses. Since each |
| 201 // DnsUDPAttempt binds to a different port, we might find that responses | 205 // DnsUDPAttempt binds to a different port, we might find that responses |
| 202 // to previously timed out queries lead to failures in the future. | 206 // to previously timed out queries lead to failures in the future. |
| 203 // http://crbug.com/107413 | 207 // Our solution is to make another attempt, in case the query truly |
| 204 return ERR_DNS_MALFORMED_RESPONSE; | 208 // failed, but keep this attempt alive, in case it was a false alarm. |
| 209 received_malformed_response_ = true; | |
| 210 next_state_ = STATE_READ_RESPONSE; | |
| 211 return OK; | |
| 205 } | 212 } |
| 206 if (response_->flags() & dns_protocol::kFlagTC) | 213 if (response_->flags() & dns_protocol::kFlagTC) |
| 207 return ERR_DNS_SERVER_REQUIRES_TCP; | 214 return ERR_DNS_SERVER_REQUIRES_TCP; |
| 208 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 | 215 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 |
| 209 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) | 216 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) |
| 210 return ERR_NAME_NOT_RESOLVED; | 217 return ERR_NAME_NOT_RESOLVED; |
| 211 if (response_->rcode() != dns_protocol::kRcodeNOERROR) | 218 if (response_->rcode() != dns_protocol::kRcodeNOERROR) |
| 212 return ERR_DNS_SERVER_FAILED; | 219 return ERR_DNS_SERVER_FAILED; |
| 213 | 220 |
| 214 CHECK(response()); | 221 CHECK(response()); |
| 215 return OK; | 222 return OK; |
| 216 } | 223 } |
| 217 | 224 |
| 218 void OnIOComplete(int rv) { | 225 void OnIOComplete(int rv) { |
| 219 rv = DoLoop(rv); | 226 rv = DoLoop(rv); |
| 220 if (rv != ERR_IO_PENDING) | 227 if (rv != ERR_IO_PENDING) |
| 221 callback_.Run(rv); | 228 callback_.Run(rv); |
| 222 } | 229 } |
| 223 | 230 |
| 224 State next_state_; | 231 State next_state_; |
| 232 bool received_malformed_response_; | |
| 225 | 233 |
| 226 scoped_ptr<DatagramClientSocket> socket_; | 234 scoped_ptr<DatagramClientSocket> socket_; |
| 227 IPEndPoint server_; | 235 IPEndPoint server_; |
| 228 scoped_ptr<DnsQuery> query_; | 236 scoped_ptr<DnsQuery> query_; |
| 229 | 237 |
| 230 scoped_ptr<DnsResponse> response_; | 238 scoped_ptr<DnsResponse> response_; |
| 231 | 239 |
| 232 CompletionCallback callback_; | 240 CompletionCallback callback_; |
| 233 | 241 |
| 234 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 242 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 break; | 511 break; |
| 504 default: | 512 default: |
| 505 // Server failure. | 513 // Server failure. |
| 506 DCHECK(result.attempt); | 514 DCHECK(result.attempt); |
| 507 if (result.attempt != attempts_.back()) { | 515 if (result.attempt != attempts_.back()) { |
| 508 // This attempt already timed out. Ignore it. | 516 // This attempt already timed out. Ignore it. |
| 509 return AttemptResult(ERR_IO_PENDING, NULL); | 517 return AttemptResult(ERR_IO_PENDING, NULL); |
| 510 } | 518 } |
| 511 if (MoreAttemptsAllowed()) { | 519 if (MoreAttemptsAllowed()) { |
| 512 result = MakeAttempt(); | 520 result = MakeAttempt(); |
| 513 } else { | 521 } else if (result.rv != ERR_DNS_MALFORMED_RESPONSE) { |
| 514 return AttemptResult(result.rv, NULL); | 522 return AttemptResult(result.rv, NULL); |
| 515 } | 523 } // else wait until attempt times out. |
| 516 break; | 524 break; |
| 517 } | 525 } |
| 518 } | 526 } |
| 519 return result; | 527 return result; |
| 520 } | 528 } |
| 521 | 529 |
| 522 void OnTimeout() { | 530 void OnTimeout() { |
| 523 if (callback_.is_null()) | 531 if (callback_.is_null()) |
| 524 return; | 532 return; |
| 525 AttemptResult result = FinishAttempt( | 533 AttemptResult result = FinishAttempt( |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 } // namespace | 587 } // namespace |
| 580 | 588 |
| 581 // static | 589 // static |
| 582 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 590 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( |
| 583 DnsSession* session) { | 591 DnsSession* session) { |
| 584 return scoped_ptr<DnsTransactionFactory>( | 592 return scoped_ptr<DnsTransactionFactory>( |
| 585 new DnsTransactionFactoryImpl(session)); | 593 new DnsTransactionFactoryImpl(session)); |
| 586 } | 594 } |
| 587 | 595 |
| 588 } // namespace net | 596 } // namespace net |
| OLD | NEW |