Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <deque> | |
| 6 #include <string> | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/memory/weak_ptr.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/rand_util.h" | |
| 15 #include "base/stl_util.h" | |
| 16 #include "base/string_piece.h" | |
| 17 #include "base/threading/non_thread_safe.h" | |
| 18 #include "base/timer.h" | |
| 19 #include "net/base/completion_callback.h" | |
| 20 #include "net/base/dns_util.h" | |
| 21 #include "net/base/io_buffer.h" | |
| 22 #include "net/base/ip_endpoint.h" | |
| 23 #include "net/base/net_errors.h" | |
| 24 #include "net/base/net_log.h" | |
| 5 #include "net/dns/dns_client.h" | 25 #include "net/dns/dns_client.h" |
|
mmenke
2012/01/13 16:44:37
This should go first, above the other includes, pe
| |
| 6 | 26 #include "net/dns/dns_protocol.h" |
| 7 #include "base/bind.h" | 27 #include "net/dns/dns_query.h" |
| 8 #include "base/string_piece.h" | |
| 9 #include "net/base/net_errors.h" | |
| 10 #include "net/dns/dns_response.h" | 28 #include "net/dns/dns_response.h" |
| 11 #include "net/dns/dns_session.h" | 29 #include "net/dns/dns_session.h" |
| 12 #include "net/dns/dns_transaction.h" | |
| 13 #include "net/socket/client_socket_factory.h" | 30 #include "net/socket/client_socket_factory.h" |
| 31 #include "net/udp/datagram_client_socket.h" | |
| 14 | 32 |
| 15 namespace net { | 33 namespace net { |
| 16 | 34 |
| 17 DnsClient::Request::Request(const base::StringPiece& qname, | 35 namespace { |
| 18 uint16 qtype, | 36 |
| 19 const RequestCallback& callback) | 37 // Count labels in the fully-qualified name in DNS format. |
| 20 : qname_(qname.data(), qname.size()), | 38 int CountLabels(const std::string& name) { |
| 39 size_t count = 0; | |
| 40 for (size_t i = 0; i < name.size() && name[i]; i+= name[i] + 1) | |
|
cbentzel
2012/01/13 13:39:54
Nit: space between i and +=
| |
| 41 ++count; | |
| 42 return count; | |
| 43 } | |
| 44 | |
| 45 class StartParameters : public NetLog::EventParameters { | |
| 46 public: | |
| 47 StartParameters(const std::string& hostname, | |
| 48 uint16 qtype, | |
| 49 const NetLog::Source& source) | |
| 50 : hostname_(hostname), qtype_(qtype), source_(source) {} | |
| 51 | |
| 52 virtual Value* ToValue() const { | |
|
mmenke
2012/01/13 16:44:37
nit: OVERRIDE
| |
| 53 DictionaryValue* dict = new DictionaryValue(); | |
| 54 dict->SetString("hostname", hostname_); | |
| 55 dict->SetInteger("query_type", qtype_); | |
| 56 dict->Set("source_dependency", source_.ToValue()); | |
| 57 return dict; | |
| 58 } | |
| 59 | |
| 60 private: | |
| 61 std::string hostname_; | |
| 62 uint16 qtype_; | |
|
mmenke
2012/01/13 16:44:37
nit: Both of these can be const
| |
| 63 const NetLog::Source source_; | |
| 64 }; | |
| 65 | |
| 66 class ResponseParameters : public NetLog::EventParameters { | |
| 67 public: | |
| 68 ResponseParameters(int rcode, int answer_count, const NetLog::Source& source) | |
| 69 : rcode_(rcode), answer_count_(answer_count), source_(source) {} | |
| 70 | |
| 71 virtual Value* ToValue() const { | |
|
mmenke
2012/01/13 16:44:37
nit: OVERRIDE
| |
| 72 DictionaryValue* dict = new DictionaryValue(); | |
| 73 dict->SetInteger("rcode", rcode_); | |
| 74 dict->SetInteger("answer_count", answer_count_); | |
| 75 dict->Set("source_dependency", source_.ToValue()); | |
| 76 return dict; | |
| 77 } | |
| 78 | |
| 79 private: | |
| 80 int rcode_; | |
| 81 int answer_count_; | |
|
mmenke
2012/01/13 16:44:37
nit: Both of these can be const
| |
| 82 const NetLog::Source source_; | |
| 83 }; | |
| 84 | |
| 85 // ---------------------------------------------------------------------------- | |
| 86 | |
| 87 // A single asynchronous DNS exchange over UDP, which consists of sending out a | |
| 88 // DNS query, waiting for a response, and returning the response that it | |
| 89 // matches. Logging is done in the socket and in the outer DnsTransaction. | |
| 90 class DnsUDPAttempt { | |
| 91 public: | |
| 92 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, | |
| 93 const IPEndPoint& server, | |
| 94 scoped_ptr<DnsQuery> query, | |
| 95 const CompletionCallback& callback) | |
| 96 : next_state_(STATE_NONE), | |
| 97 socket_(socket.Pass()), | |
| 98 server_(server), | |
| 99 query_(query.Pass()), | |
| 100 callback_(callback) { | |
| 101 } | |
| 102 | |
| 103 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | |
| 104 // and calls |callback| upon completion. | |
| 105 int Start() { | |
| 106 DCHECK_EQ(STATE_NONE, next_state_); | |
| 107 next_state_ = STATE_CONNECT; | |
| 108 return DoLoop(OK); | |
| 109 } | |
| 110 | |
| 111 const DnsQuery* query() { | |
|
mmenke
2012/01/13 16:44:37
nit: const
| |
| 112 return query_.get(); | |
| 113 } | |
| 114 | |
| 115 const DatagramClientSocket* socket() const { | |
| 116 return socket_.get(); | |
| 117 } | |
| 118 | |
| 119 // Returns the response or NULL if has not received a matching response from | |
| 120 // the server. | |
| 121 const DnsResponse* response() const { | |
| 122 return (response_.get() != NULL && response_->Parser().IsValid()) ? | |
| 123 response_.get() : NULL; | |
| 124 } | |
| 125 | |
| 126 private: | |
| 127 enum State { | |
| 128 STATE_CONNECT, | |
| 129 STATE_SEND_QUERY, | |
| 130 STATE_SEND_QUERY_COMPLETE, | |
| 131 STATE_READ_RESPONSE, | |
| 132 STATE_READ_RESPONSE_COMPLETE, | |
| 133 STATE_NONE, | |
| 134 }; | |
| 135 | |
| 136 int DoLoop(int result) { | |
| 137 DCHECK_NE(STATE_NONE, next_state_); | |
| 138 int rv = result; | |
| 139 do { | |
| 140 State state = next_state_; | |
| 141 next_state_ = STATE_NONE; | |
| 142 switch (state) { | |
| 143 case STATE_CONNECT: | |
| 144 rv = DoConnect(); | |
| 145 break; | |
| 146 case STATE_SEND_QUERY: | |
| 147 rv = DoSendQuery(); | |
| 148 break; | |
| 149 case STATE_SEND_QUERY_COMPLETE: | |
| 150 rv = DoSendQueryComplete(rv); | |
| 151 break; | |
| 152 case STATE_READ_RESPONSE: | |
| 153 rv = DoReadResponse(); | |
| 154 break; | |
| 155 case STATE_READ_RESPONSE_COMPLETE: | |
| 156 rv = DoReadResponseComplete(rv); | |
| 157 break; | |
| 158 default: | |
| 159 NOTREACHED(); | |
| 160 break; | |
| 161 } | |
| 162 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | |
| 163 | |
| 164 return rv; | |
| 165 } | |
| 166 | |
| 167 int DoConnect() { | |
| 168 next_state_ = STATE_SEND_QUERY; | |
| 169 return socket_->Connect(server_); | |
| 170 } | |
| 171 | |
| 172 int DoSendQuery() { | |
| 173 next_state_ = STATE_SEND_QUERY_COMPLETE; | |
| 174 return socket_->Write(query_->io_buffer(), | |
| 175 query_->io_buffer()->size(), | |
| 176 base::Bind(&DnsUDPAttempt::OnIOComplete, | |
| 177 base::Unretained(this))); | |
| 178 } | |
| 179 | |
| 180 int DoSendQueryComplete(int rv) { | |
| 181 if (rv < 0) | |
| 182 return rv; | |
| 183 | |
| 184 // Writing to UDP should not result in a partial datagram. | |
| 185 if (rv != query_->io_buffer()->size()) | |
| 186 return ERR_MSG_TOO_BIG; | |
| 187 | |
| 188 next_state_ = STATE_READ_RESPONSE; | |
| 189 return OK; | |
| 190 } | |
| 191 | |
| 192 int DoReadResponse() { | |
| 193 next_state_ = STATE_READ_RESPONSE_COMPLETE; | |
| 194 response_.reset(new DnsResponse()); | |
| 195 return socket_->Read(response_->io_buffer(), | |
| 196 response_->io_buffer()->size(), | |
| 197 base::Bind(&DnsUDPAttempt::OnIOComplete, | |
| 198 base::Unretained(this))); | |
| 199 } | |
| 200 | |
| 201 int DoReadResponseComplete(int rv) { | |
| 202 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 203 if (rv < 0) | |
| 204 return rv; | |
| 205 | |
| 206 DCHECK(rv); | |
| 207 if (!response_->InitParse(rv, *query_)) | |
| 208 return ERR_DNS_MALFORMED_RESPONSE; | |
| 209 if (response_->flags() & dns_protocol::kFlagTC) | |
| 210 return ERR_DNS_SERVER_REQUIRES_TCP; | |
| 211 if (response_->rcode() != dns_protocol::kRcodeNOERROR && | |
| 212 response_->rcode() != dns_protocol::kRcodeNXDOMAIN) { | |
| 213 return ERR_DNS_SERVER_FAILED; | |
| 214 } | |
| 215 if (response_->answer_count() == 0) | |
| 216 return ERR_NAME_NOT_RESOLVED; | |
| 217 | |
| 218 return OK; | |
| 219 } | |
| 220 | |
| 221 void OnIOComplete(int rv) { | |
| 222 rv = DoLoop(rv); | |
| 223 if (rv != ERR_IO_PENDING) | |
| 224 callback_.Run(rv); | |
| 225 } | |
| 226 | |
| 227 State next_state_; | |
| 228 | |
| 229 scoped_ptr<DatagramClientSocket> socket_; | |
| 230 IPEndPoint server_; | |
| 231 scoped_ptr<DnsQuery> query_; | |
| 232 | |
| 233 scoped_ptr<DnsResponse> response_; | |
| 234 | |
| 235 CompletionCallback callback_; | |
|
mmenke
2012/01/13 16:44:37
nit: DISALLOW_COPY_AND_ASSIGN
| |
| 236 }; | |
| 237 | |
| 238 // ---------------------------------------------------------------------------- | |
| 239 | |
| 240 // Implements DnsTransaction. Configuration is supplied by DnsSession. | |
| 241 // The suffix list is built according to the DnsConfig from the session. | |
| 242 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. | |
| 243 // The first server to attempt on each query is given by | |
| 244 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. | |
| 245 // Each server is attempted DnsConfig::attempts times. | |
| 246 class DnsTransactionImpl : public DnsTransaction, | |
| 247 public base::NonThreadSafe, | |
| 248 public base::SupportsWeakPtr<DnsTransactionImpl> { | |
| 249 public: | |
| 250 DnsTransactionImpl(DnsSession* session, | |
| 251 const std::string& hostname, | |
| 252 uint16 qtype, | |
| 253 const DnsClient::CallbackType& callback, | |
| 254 const BoundNetLog& source_net_log) | |
| 255 : session_(session), | |
| 256 hostname_(hostname), | |
| 21 qtype_(qtype), | 257 qtype_(qtype), |
| 22 callback_(callback) { | 258 callback_(callback), |
| 23 } | 259 net_log_(BoundNetLog::Make(session->net_log(), |
| 24 | 260 NetLog::SOURCE_DNS_TRANSACTION)), |
| 25 DnsClient::Request::~Request() {} | 261 successful_attempt_(NULL) { |
|
cbentzel
2012/01/13 13:39:54
first_server_index_ should be initialized - yeah,
| |
| 26 | 262 DCHECK(session_); |
| 27 // Implementation of DnsClient that uses DnsTransaction to serve requests. | 263 DCHECK(!hostname_.empty()); |
| 264 DCHECK(!callback_.is_null()); | |
| 265 | |
|
cbentzel
2012/01/13 13:39:54
Should this check if qtype is one of the known typ
| |
| 266 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, make_scoped_refptr( | |
| 267 new StartParameters(hostname_, qtype_, source_net_log.source()))); | |
| 268 | |
| 269 int rv = PrepareSearch(); | |
|
cbentzel
2012/01/13 13:39:54
Not really sure if I like having all this in the c
szym
2012/01/13 15:43:40
Do you mean move PrepareSearch to Start? I'd rathe
cbentzel
2012/01/13 18:12:59
I did mean do it in DnsClient::CreateTransaction,
| |
| 270 if (rv == OK) | |
| 271 rv = StartQuery(); | |
| 272 if (rv != ERR_IO_PENDING) { | |
| 273 DCHECK_NE(OK, rv); | |
| 274 DCHECK_NE(ERR_NAME_NOT_RESOLVED, rv); | |
| 275 // Unexpected synchronous completion. Use WeakPtr in case the user | |
| 276 // destroys the transaction before the task is executed. | |
| 277 MessageLoop::current()->PostTask( | |
| 278 FROM_HERE, | |
| 279 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), rv)); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 virtual ~DnsTransactionImpl() { | |
| 284 STLDeleteElements(&attempts_); | |
| 285 if (!callback_.is_null()) { | |
| 286 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); | |
| 287 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, | |
| 288 ERR_ABORTED); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 virtual const std::string& GetHostname() const OVERRIDE { | |
| 293 DCHECK(CalledOnValidThread()); | |
| 294 return hostname_; | |
| 295 } | |
| 296 | |
| 297 virtual uint16 GetType() const OVERRIDE { | |
| 298 DCHECK(CalledOnValidThread()); | |
| 299 return qtype_; | |
| 300 } | |
| 301 | |
| 302 private: | |
| 303 // Prepares |qnames_| according to the DnsConfig. | |
| 304 int PrepareSearch() { | |
| 305 const DnsConfig& config = session_->config(); | |
| 306 | |
| 307 std::string hostname; | |
|
cbentzel
2012/01/13 13:39:54
It would be nice to use a better variable name tha
szym
2012/01/13 15:43:40
I could use dotted_hostname for the other case.
| |
| 308 if (!DNSDomainFromDot(hostname_, &hostname)) | |
| 309 return ERR_INVALID_ARGUMENT; | |
| 310 | |
| 311 if (hostname_[hostname_.size() - 1] == '.') { | |
| 312 // It's a fully-qualified name, no suffix search. | |
| 313 qnames_.push_back(hostname); | |
| 314 return OK; | |
| 315 } | |
| 316 | |
| 317 // Set true when |hostname| is put on the list. | |
| 318 bool had_hostname = false; | |
| 319 | |
| 320 int ndots = CountLabels(hostname) - 1; | |
| 321 if (ndots >= config.ndots) { | |
| 322 qnames_.push_back(hostname); | |
| 323 had_hostname = true; | |
| 324 } | |
| 325 | |
| 326 std::string qname; | |
| 327 for (size_t i = 0; i < config.search.size(); ++i) { | |
| 328 // Ignore invalid (too long) combinations. | |
| 329 if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname)) | |
| 330 continue; | |
| 331 if (qname.size() == hostname.size()) { | |
|
cbentzel
2012/01/13 13:39:54
Interesting - is an empty suffix allowed? Or is th
szym
2012/01/13 15:43:40
DNSDomainFromDot always appends the root domain at
| |
| 332 if (had_hostname) | |
|
cbentzel
2012/01/13 13:39:54
Do you want to make this more generic in the loop
szym
2012/01/13 15:43:40
I think it'd make sense to do this filtering at th
| |
| 333 continue; | |
| 334 had_hostname = true; | |
| 335 } | |
| 336 qnames_.push_back(qname); | |
| 337 } | |
| 338 | |
| 339 if (!had_hostname) | |
| 340 qnames_.push_back(hostname); | |
| 341 | |
| 342 return OK; | |
| 343 } | |
| 344 | |
| 345 void DoCallback(int rv) { | |
| 346 if (callback_.is_null()) | |
| 347 return; | |
| 348 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 349 DCHECK(rv != OK || successful_attempt_ != NULL); | |
| 350 | |
| 351 DnsClient::CallbackType callback = callback_; | |
| 352 callback_.Reset(); | |
| 353 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv); | |
| 354 callback.Run(this, | |
| 355 rv, | |
| 356 successful_attempt_ ? successful_attempt_->response() : NULL); | |
| 357 } | |
| 358 | |
| 359 // Makes another attempt at the current name, |qnames_.front()|, using the | |
| 360 // next nameserver. | |
| 361 int MakeAttempt() { | |
| 362 int attempt_number = attempts_.size(); | |
| 363 | |
| 364 scoped_ptr<DatagramClientSocket> socket( | |
| 365 session_->socket_factory()->CreateDatagramClientSocket( | |
| 366 DatagramSocket::RANDOM_BIND, | |
| 367 base::Bind(&base::RandInt), | |
| 368 net_log_.net_log(), | |
| 369 net_log_.source())); | |
| 370 | |
| 371 uint16 id = session_->NextQueryId(); | |
| 372 scoped_ptr<DnsQuery> query; | |
| 373 if (attempts_.empty()) { | |
| 374 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | |
| 375 } else { | |
| 376 query.reset(attempts_[0]->query()->CloneWithNewId(id)); | |
|
cbentzel
2012/01/13 13:39:54
Note to self: See if this any easier.
| |
| 377 } | |
| 378 | |
| 379 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, make_scoped_refptr( | |
| 380 new NetLogSourceParameter("socket", socket->NetLog().source()))); | |
|
mmenke
2012/01/13 16:44:37
Think it would be a little clearer if you also log
szym
2012/01/13 17:17:42
The reason why I don't include attempt_number is b
mmenke
2012/01/13 17:22:58
I was just thinking that it would be clearer for t
| |
| 381 | |
| 382 const DnsConfig& config = session_->config(); | |
| 383 | |
| 384 int server_index = first_server_index_ + | |
|
cbentzel
2012/01/13 13:39:54
You should check for 0 length config.nameservers,
szym
2012/01/13 15:43:40
If |config.nameservers| is empty, the config is in
cbentzel
2012/01/13 18:12:59
What if the config changed while the DnsTransactio
szym
2012/01/13 20:06:17
DnsConfig is const in DnsSession, so DnsTransactio
| |
| 385 (attempt_number % config.nameservers.size()); | |
| 386 | |
| 387 DnsUDPAttempt* attempt = new DnsUDPAttempt( | |
| 388 socket.Pass(), | |
| 389 config.nameservers[server_index], | |
| 390 query.Pass(), | |
| 391 base::Bind(&DnsTransactionImpl::OnAttemptComplete, | |
| 392 base::Unretained(this), | |
| 393 attempt_number)); | |
| 394 | |
| 395 base::TimeDelta timeout = session_->NextTimeout(attempt_number); | |
| 396 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | |
| 397 attempts_.push_back(attempt); | |
| 398 return attempt->Start(); | |
| 399 } | |
| 400 | |
| 401 // Begins query for the current name. Makes the first attempt. | |
| 402 int StartQuery() { | |
| 403 std::string dotted_qname = DNSDomainToString(qnames_.front()); | |
| 404 net_log_.BeginEvent( | |
| 405 NetLog::TYPE_DNS_TRANSACTION_QUERY, | |
|
mmenke
2012/01/13 17:16:24
Where do you log the corresponding end event?
| |
| 406 make_scoped_refptr(new NetLogStringParameter("qname", dotted_qname))); | |
| 407 | |
| 408 first_server_index_ = session_->NextFirstServerIndex(); | |
| 409 | |
| 410 STLDeleteElements(&attempts_); | |
| 411 return MakeAttempt(); | |
| 412 } | |
| 413 | |
| 414 void OnAttemptComplete(int attempt_number, int rv) { | |
| 415 timer_.Stop(); | |
| 416 | |
| 417 const DnsUDPAttempt* attempt = attempts_[attempt_number]; | |
| 418 | |
| 419 net_log_.AddEvent( | |
| 420 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, | |
| 421 make_scoped_refptr( | |
| 422 new NetLogSourceParameter("socket", | |
| 423 attempt->socket()->NetLog().source()))); | |
| 424 | |
| 425 switch (rv) { | |
| 426 case ERR_NAME_NOT_RESOLVED: | |
| 427 // Try next suffix. | |
| 428 qnames_.pop_front(); | |
| 429 if (qnames_.empty()) | |
| 430 rv = ERR_NAME_NOT_RESOLVED; | |
| 431 else | |
| 432 rv = StartQuery(); | |
| 433 break; | |
| 434 case OK: | |
| 435 successful_attempt_ = attempt; | |
| 436 break; | |
| 437 default: | |
| 438 // TODO(szym): Some nameservers could fail and we should just ignore | |
| 439 // them. | |
| 440 break; | |
| 441 } | |
| 442 if (rv != ERR_IO_PENDING) | |
| 443 DoCallback(rv); | |
| 444 } | |
| 445 | |
| 446 void OnTimeout() { | |
| 447 const DnsConfig& config = session_->config(); | |
| 448 if (attempts_.size() == config.attempts * config.nameservers.size()) { | |
| 449 DoCallback(ERR_DNS_TIMED_OUT); | |
| 450 return; | |
| 451 } | |
| 452 int rv = MakeAttempt(); | |
| 453 if (rv != ERR_IO_PENDING) | |
| 454 DoCallback(rv); | |
| 455 } | |
| 456 | |
| 457 scoped_refptr<DnsSession> session_; | |
| 458 std::string hostname_; | |
| 459 uint16 qtype_; | |
| 460 // Set to NULL once the transaction completes. | |
|
cbentzel
2012/01/13 13:39:54
Nit: perhaps null instead of NULL - NULL implies p
| |
| 461 DnsClient::CallbackType callback_; | |
| 462 | |
| 463 BoundNetLog net_log_; | |
| 464 | |
| 465 // Search list of fully-qualified DNS names to query next (in DNS format). | |
| 466 std::deque<std::string> qnames_; | |
|
cbentzel
2012/01/13 13:39:54
deque not really needed here, since just doing pus
szym
2012/01/13 15:43:40
Need qnames_.pop_front().
| |
| 467 | |
| 468 // List of attempts for the current name. | |
| 469 std::vector<DnsUDPAttempt*> attempts_; | |
| 470 // The one of the |attempts_| that succeeded first. | |
|
mmenke
2012/01/13 16:44:37
Nit: This is the member of |attempts_| that succe
| |
| 471 const DnsUDPAttempt* successful_attempt_; | |
| 472 | |
| 473 // Index of the first server to try on each search query. | |
| 474 int first_server_index_; | |
| 475 | |
| 476 base::OneShotTimer<DnsTransactionImpl> timer_; | |
| 477 | |
| 478 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); | |
| 479 }; | |
| 480 | |
| 481 // ---------------------------------------------------------------------------- | |
| 482 | |
| 483 // Implementation of DnsClient that returns instances of DnsTransactionImpl. | |
| 28 class DnsClientImpl : public DnsClient { | 484 class DnsClientImpl : public DnsClient { |
|
mmenke
2012/01/13 16:44:37
Is there a compelling reason to keep DnsClient and
szym
2012/01/13 17:17:42
The reason I'd keep them separate is so that we ca
mmenke
2012/01/13 17:22:58
Ah, right. Sounds good to me.
| |
| 29 public: | 485 public: |
| 30 class RequestImpl : public Request { | |
| 31 public: | |
| 32 RequestImpl(const base::StringPiece& qname, | |
| 33 uint16 qtype, | |
| 34 const RequestCallback& callback, | |
| 35 DnsSession* session, | |
| 36 const BoundNetLog& net_log) | |
| 37 : Request(qname, qtype, callback), | |
| 38 session_(session), | |
| 39 net_log_(net_log) { | |
| 40 } | |
| 41 | |
| 42 virtual int Start() OVERRIDE { | |
| 43 transaction_.reset(new DnsTransaction( | |
| 44 session_, | |
| 45 qname(), | |
| 46 qtype(), | |
| 47 base::Bind(&RequestImpl::OnComplete, base::Unretained(this)), | |
| 48 net_log_)); | |
| 49 return transaction_->Start(); | |
| 50 } | |
| 51 | |
| 52 void OnComplete(DnsTransaction* transaction, int rv) { | |
| 53 DCHECK_EQ(transaction_.get(), transaction); | |
| 54 // TODO(szym): | |
| 55 // - handle retransmissions here instead of DnsTransaction | |
| 56 // - handle rcode and flags here instead of DnsTransaction | |
| 57 // - update RTT in DnsSession | |
| 58 // - perform suffix search | |
| 59 // - handle DNS over TCP | |
| 60 DoCallback(rv, (rv == OK) ? transaction->response() : NULL); | |
| 61 } | |
| 62 | |
| 63 private: | |
| 64 scoped_refptr<DnsSession> session_; | |
| 65 BoundNetLog net_log_; | |
| 66 scoped_ptr<DnsTransaction> transaction_; | |
| 67 }; | |
| 68 | |
| 69 explicit DnsClientImpl(DnsSession* session) { | 486 explicit DnsClientImpl(DnsSession* session) { |
| 70 session_ = session; | 487 session_ = session; |
| 71 } | 488 } |
| 72 | 489 |
| 73 virtual Request* CreateRequest( | 490 virtual scoped_ptr<DnsTransaction> CreateTransaction( |
| 74 const base::StringPiece& qname, | 491 const std::string& hostname, |
| 75 uint16 qtype, | 492 uint16 qtype, |
| 76 const RequestCallback& callback, | 493 const CallbackType& callback, |
| 77 const BoundNetLog& source_net_log) OVERRIDE { | 494 const BoundNetLog& source_net_log) OVERRIDE { |
| 78 return new RequestImpl(qname, qtype, callback, session_, source_net_log); | 495 return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(session_, |
| 496 hostname, | |
| 497 qtype, | |
| 498 callback, | |
| 499 source_net_log)); | |
| 79 } | 500 } |
| 80 | 501 |
| 81 private: | 502 private: |
| 82 scoped_refptr<DnsSession> session_; | 503 scoped_refptr<DnsSession> session_; |
| 83 }; | 504 }; |
| 84 | 505 |
| 506 } // namespace | |
| 507 | |
| 85 // static | 508 // static |
| 86 DnsClient* DnsClient::CreateClient(DnsSession* session) { | 509 scoped_ptr<DnsClient> DnsClient::CreateClient(DnsSession* session) { |
| 87 return new DnsClientImpl(session); | 510 return scoped_ptr<DnsClient>(new DnsClientImpl(session)); |
| 88 } | 511 } |
| 89 | 512 |
| 90 } // namespace net | 513 } // namespace net |
| 91 | 514 |
| OLD | NEW |