| 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 "net/dns/dns_transaction.h" |    5 #include "net/dns/dns_transaction.h" | 
|    6  |    6  | 
|    7 #include "base/bind.h" |    7 #include "base/bind.h" | 
|    8 #include "base/rand_util.h" |    8 #include "base/rand_util.h" | 
|    9 #include "base/values.h" |    9 #include "base/values.h" | 
|   10 #include "net/base/dns_util.h" |  | 
|   11 #include "net/base/io_buffer.h" |   10 #include "net/base/io_buffer.h" | 
|   12 #include "net/base/net_errors.h" |   11 #include "net/base/net_errors.h" | 
 |   12 #include "net/dns/dns_protocol.h" | 
|   13 #include "net/dns/dns_query.h" |   13 #include "net/dns/dns_query.h" | 
|   14 #include "net/dns/dns_response.h" |   14 #include "net/dns/dns_response.h" | 
 |   15 #include "net/dns/dns_session.h" | 
|   15 #include "net/socket/client_socket_factory.h" |   16 #include "net/socket/client_socket_factory.h" | 
|   16 #include "net/udp/datagram_client_socket.h" |   17 #include "net/udp/datagram_client_socket.h" | 
|   17  |   18  | 
|   18 namespace net { |   19 namespace net { | 
|   19  |   20  | 
|   20 namespace { |   21 namespace { | 
|   21  |   22  | 
|   22 // Retry timeouts. |  | 
|   23 const int kTimeoutsMs[] = {3000, 5000, 11000}; |  | 
|   24 const int kMaxAttempts = arraysize(kTimeoutsMs); |  | 
|   25  |  | 
|   26 // Returns the string representation of an IPAddressNumber. |  | 
|   27 std::string IPAddressToString(const IPAddressNumber& ip_address) { |  | 
|   28   IPEndPoint ip_endpoint(ip_address, 0); |  | 
|   29   struct sockaddr_storage addr; |  | 
|   30   size_t addr_len = sizeof(addr); |  | 
|   31   struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr); |  | 
|   32   if (!ip_endpoint.ToSockAddr(sockaddr, &addr_len)) |  | 
|   33     return ""; |  | 
|   34   return NetAddressToString(sockaddr, addr_len); |  | 
|   35 } |  | 
|   36  |  | 
|   37 } |  | 
|   38  |  | 
|   39 DnsTransaction::Delegate::Delegate() { |  | 
|   40 } |  | 
|   41  |  | 
|   42 DnsTransaction::Delegate::~Delegate() { |  | 
|   43   while (!registered_transactions_.empty()) { |  | 
|   44     DnsTransaction* transaction = *registered_transactions_.begin(); |  | 
|   45     transaction->SetDelegate(NULL); |  | 
|   46   } |  | 
|   47   DCHECK(registered_transactions_.empty()); |  | 
|   48 } |  | 
|   49  |  | 
|   50 void DnsTransaction::Delegate::OnTransactionComplete( |  | 
|   51     int result, |  | 
|   52     const DnsTransaction* transaction, |  | 
|   53     const IPAddressList& ip_addresses) { |  | 
|   54 } |  | 
|   55  |  | 
|   56 void DnsTransaction::Delegate::Attach(DnsTransaction* transaction) { |  | 
|   57   DCHECK(registered_transactions_.find(transaction) == |  | 
|   58          registered_transactions_.end()); |  | 
|   59   registered_transactions_.insert(transaction); |  | 
|   60 } |  | 
|   61  |  | 
|   62 void DnsTransaction::Delegate::Detach(DnsTransaction* transaction) { |  | 
|   63   DCHECK(registered_transactions_.find(transaction) != |  | 
|   64          registered_transactions_.end()); |  | 
|   65   registered_transactions_.erase(transaction); |  | 
|   66 } |  | 
|   67  |  | 
|   68 namespace { |  | 
|   69  |  | 
|   70 class DnsTransactionStartParameters : public NetLog::EventParameters { |   23 class DnsTransactionStartParameters : public NetLog::EventParameters { | 
|   71  public: |   24  public: | 
|   72   DnsTransactionStartParameters(const IPEndPoint& dns_server, |   25   DnsTransactionStartParameters(const IPEndPoint& dns_server, | 
|   73                                 const DnsTransaction::Key& key, |   26                                 const base::StringPiece& qname, | 
 |   27                                 uint16 qtype, | 
|   74                                 const NetLog::Source& source) |   28                                 const NetLog::Source& source) | 
|   75       : dns_server_(dns_server), key_(key), source_(source) {} |   29       : dns_server_(dns_server), | 
 |   30         qname_(qname.data(), qname.length()), | 
 |   31         qtype_(qtype), | 
 |   32         source_(source) {} | 
|   76  |   33  | 
|   77   virtual Value* ToValue() const { |   34   virtual Value* ToValue() const { | 
|   78     std::string hostname; |  | 
|   79     DnsResponseBuffer( |  | 
|   80         reinterpret_cast<const uint8*>(key_.first.c_str()), key_.first.size()). |  | 
|   81             DNSName(&hostname); |  | 
|   82  |  | 
|   83     DictionaryValue* dict = new DictionaryValue(); |   35     DictionaryValue* dict = new DictionaryValue(); | 
|   84     dict->SetString("dns_server", dns_server_.ToString()); |   36     dict->SetString("dns_server", dns_server_.ToString()); | 
|   85     dict->SetString("hostname", hostname); |   37     dict->SetString("hostname", qname_); | 
|   86     dict->SetInteger("query_type", key_.second); |   38     dict->SetInteger("query_type", qtype_); | 
|   87     if (source_.is_valid()) |   39     if (source_.is_valid()) | 
|   88       dict->Set("source_dependency", source_.ToValue()); |   40       dict->Set("source_dependency", source_.ToValue()); | 
|   89     return dict; |   41     return dict; | 
|   90   } |   42   } | 
|   91  |   43  | 
|   92  private: |   44  private: | 
|   93   const IPEndPoint dns_server_; |   45   IPEndPoint dns_server_; | 
|   94   const DnsTransaction::Key key_; |   46   std::string qname_; | 
 |   47   uint16 qtype_; | 
|   95   const NetLog::Source source_; |   48   const NetLog::Source source_; | 
|   96 }; |   49 }; | 
|   97  |   50  | 
|   98 class DnsTransactionFinishParameters : public NetLog::EventParameters { |   51 class DnsTransactionFinishParameters : public NetLog::EventParameters { | 
|   99  public: |   52  public: | 
|  100   DnsTransactionFinishParameters(int net_error, |   53   // TODO(szym): add rcode ? | 
|  101                                  const IPAddressList& ip_address_list) |   54   DnsTransactionFinishParameters(int net_error, int answer_count) | 
|  102       : net_error_(net_error), ip_address_list_(ip_address_list) {} |   55       : net_error_(net_error), answer_count_(answer_count) {} | 
|  103  |   56  | 
|  104   virtual Value* ToValue() const { |   57   virtual Value* ToValue() const { | 
|  105     ListValue* list = new ListValue(); |  | 
|  106     for (IPAddressList::const_iterator it = ip_address_list_.begin(); |  | 
|  107          it != ip_address_list_.end(); ++it) |  | 
|  108       list->Append(Value::CreateStringValue(IPAddressToString(*it))); |  | 
|  109  |  | 
|  110     DictionaryValue* dict = new DictionaryValue(); |   58     DictionaryValue* dict = new DictionaryValue(); | 
|  111     if (net_error_) |   59     if (net_error_) | 
|  112       dict->SetInteger("net_error", net_error_); |   60       dict->SetInteger("net_error", net_error_); | 
|  113     dict->Set("address_list", list); |   61     dict->SetInteger("answer_count", answer_count_); | 
|  114     return dict; |   62     return dict; | 
|  115   } |   63   } | 
|  116  |   64  | 
|  117  private: |   65  private: | 
|  118   const int net_error_; |   66   const int net_error_; | 
|  119   const IPAddressList ip_address_list_; |   67   const int answer_count_; | 
|  120 }; |   68 }; | 
|  121  |   69  | 
|  122 class DnsTransactionRetryParameters : public NetLog::EventParameters { |   70 class DnsTransactionRetryParameters : public NetLog::EventParameters { | 
|  123  public: |   71  public: | 
|  124   DnsTransactionRetryParameters(int attempt_number, |   72   DnsTransactionRetryParameters(int attempt_number, | 
|  125                                 const NetLog::Source& source) |   73                                 const NetLog::Source& source) | 
|  126       : attempt_number_(attempt_number), source_(source) {} |   74       : attempt_number_(attempt_number), source_(source) {} | 
|  127  |   75  | 
|  128   virtual Value* ToValue() const { |   76   virtual Value* ToValue() const { | 
|  129     DictionaryValue* dict = new DictionaryValue(); |   77     DictionaryValue* dict = new DictionaryValue(); | 
|  130     dict->SetInteger("attempt_number", attempt_number_); |   78     dict->SetInteger("attempt_number", attempt_number_); | 
|  131     dict->Set("source_dependency", source_.ToValue()); |   79     dict->Set("source_dependency", source_.ToValue()); | 
|  132     return dict; |   80     return dict; | 
|  133   } |   81   } | 
|  134  |   82  | 
|  135  private: |   83  private: | 
|  136   const int attempt_number_; |   84   const int attempt_number_; | 
|  137   const NetLog::Source source_; |   85   const NetLog::Source source_; | 
|  138 }; |   86 }; | 
|  139  |   87  | 
|  140 }  // namespace |   88 }  // namespace | 
|  141  |   89  | 
|  142 DnsTransaction::DnsTransaction(const IPEndPoint& dns_server, |   90  | 
|  143                                const std::string& dns_name, |   91 DnsTransaction::DnsTransaction(DnsSession* session, | 
|  144                                uint16 query_type, |   92                                const base::StringPiece& qname, | 
|  145                                const RandIntCallback& rand_int, |   93                                uint16 qtype, | 
|  146                                ClientSocketFactory* socket_factory, |   94                                const ResultCallback& callback, | 
|  147                                const BoundNetLog& source_net_log, |   95                                const BoundNetLog& source_net_log) | 
|  148                                NetLog* net_log) |   96     : session_(session), | 
|  149     : dns_server_(dns_server), |   97       dns_server_(session->NextServer()), | 
|  150       key_(dns_name, query_type), |   98       query_(new DnsQuery(session->NextId(), qname, qtype)), | 
|  151       delegate_(NULL), |   99       callback_(callback), | 
|  152       query_(new DnsQuery(dns_name, query_type, rand_int)), |  | 
|  153       attempts_(0), |  100       attempts_(0), | 
|  154       next_state_(STATE_NONE), |  101       next_state_(STATE_NONE), | 
|  155       socket_factory_(socket_factory ? socket_factory : |  | 
|  156           ClientSocketFactory::GetDefaultFactory()), |  | 
|  157       ALLOW_THIS_IN_INITIALIZER_LIST( |  102       ALLOW_THIS_IN_INITIALIZER_LIST( | 
|  158           io_callback_(this, &DnsTransaction::OnIOComplete)), |  103           io_callback_(this, &DnsTransaction::OnIOComplete)), | 
|  159       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_DNS_TRANSACTION)) { |  104       net_log_(BoundNetLog::Make(session->net_log(), | 
|  160   DCHECK(!rand_int.is_null()); |  105           NetLog::SOURCE_DNS_TRANSACTION)) { | 
|  161   for (size_t i = 0; i < arraysize(kTimeoutsMs); ++i) |  | 
|  162     timeouts_ms_.push_back(base::TimeDelta::FromMilliseconds(kTimeoutsMs[i])); |  | 
|  163   net_log_.BeginEvent( |  106   net_log_.BeginEvent( | 
|  164       NetLog::TYPE_DNS_TRANSACTION, |  107       NetLog::TYPE_DNS_TRANSACTION, | 
|  165       make_scoped_refptr( |  108       make_scoped_refptr( | 
|  166           new DnsTransactionStartParameters(dns_server_, key_, |  109           new DnsTransactionStartParameters(dns_server_, | 
 |  110                                             qname, | 
 |  111                                             qtype, | 
|  167                                             source_net_log.source()))); |  112                                             source_net_log.source()))); | 
|  168 } |  113 } | 
|  169  |  114  | 
|  170 DnsTransaction::~DnsTransaction() { |  115 DnsTransaction::~DnsTransaction() {} | 
|  171   SetDelegate(NULL); |  | 
|  172 } |  | 
|  173  |  | 
|  174 void DnsTransaction::SetDelegate(Delegate* delegate) { |  | 
|  175   if (delegate == delegate_) |  | 
|  176     return; |  | 
|  177   if (delegate_) |  | 
|  178     delegate_->Detach(this); |  | 
|  179   delegate_ = delegate; |  | 
|  180   if (delegate_) |  | 
|  181     delegate_->Attach(this); |  | 
|  182 } |  | 
|  183  |  116  | 
|  184 int DnsTransaction::Start() { |  117 int DnsTransaction::Start() { | 
|  185   DCHECK_EQ(STATE_NONE, next_state_); |  118   DCHECK_EQ(STATE_NONE, next_state_); | 
|  186   next_state_ = STATE_CONNECT; |  119   next_state_ = STATE_CONNECT; | 
|  187   return DoLoop(OK); |  120   return DoLoop(OK); | 
|  188 } |  121 } | 
|  189  |  122  | 
|  190 int DnsTransaction::DoLoop(int result) { |  123 int DnsTransaction::DoLoop(int result) { | 
|  191   DCHECK_NE(STATE_NONE, next_state_); |  124   DCHECK_NE(STATE_NONE, next_state_); | 
|  192   int rv = result; |  125   int rv = result; | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
|  216         NOTREACHED(); |  149         NOTREACHED(); | 
|  217         break; |  150         break; | 
|  218     } |  151     } | 
|  219   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |  152   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 
|  220  |  153  | 
|  221   return rv; |  154   return rv; | 
|  222 } |  155 } | 
|  223  |  156  | 
|  224 void DnsTransaction::DoCallback(int result) { |  157 void DnsTransaction::DoCallback(int result) { | 
|  225   DCHECK_NE(result, ERR_IO_PENDING); |  158   DCHECK_NE(result, ERR_IO_PENDING); | 
 |  159   int answer_count = (result == OK) ? response()->answer_count() : 0; | 
|  226   net_log_.EndEvent( |  160   net_log_.EndEvent( | 
|  227       NetLog::TYPE_DNS_TRANSACTION, |  161       NetLog::TYPE_DNS_TRANSACTION, | 
|  228       make_scoped_refptr( |  162       make_scoped_refptr( | 
|  229           new DnsTransactionFinishParameters(result, ip_addresses_))); |  163           new DnsTransactionFinishParameters(result, answer_count))); | 
|  230   if (delegate_) |  164   callback_.Run(this, result); | 
|  231     delegate_->OnTransactionComplete(result, this, ip_addresses_); |  | 
|  232 } |  165 } | 
|  233  |  166  | 
|  234 void DnsTransaction::OnIOComplete(int result) { |  167 void DnsTransaction::OnIOComplete(int result) { | 
|  235   int rv = DoLoop(result); |  168   int rv = DoLoop(result); | 
|  236   if (rv != ERR_IO_PENDING) |  169   if (rv != ERR_IO_PENDING) | 
|  237     DoCallback(rv); |  170     DoCallback(rv); | 
|  238 } |  171 } | 
|  239  |  172  | 
|  240 int DnsTransaction::DoConnect() { |  173 int DnsTransaction::DoConnect() { | 
|  241   next_state_ = STATE_CONNECT_COMPLETE; |  174   next_state_ = STATE_CONNECT_COMPLETE; | 
|  242  |  175  | 
|  243   DCHECK_LT(attempts_, timeouts_ms_.size()); |  176   StartTimer(session_->NextTimeout(attempts_)); | 
|  244   StartTimer(timeouts_ms_[attempts_]); |  177   ++attempts_; | 
|  245   attempts_++; |  | 
|  246  |  178  | 
|  247   // TODO(agayev): keep all sockets around in case the server responds |  179   // TODO(szym): keep all sockets around in case the server responds | 
|  248   // after its timeout; state machine will need to change to handle that. |  180   // after its timeout; state machine will need to change to handle that. | 
|  249   socket_.reset(socket_factory_->CreateDatagramClientSocket( |  181   // The current plan is to move socket management out to DnsSession. | 
 |  182   // Hence also move retransmissions to DnsClient::Request. | 
 |  183   socket_.reset(session_->socket_factory()->CreateDatagramClientSocket( | 
|  250       DatagramSocket::RANDOM_BIND, |  184       DatagramSocket::RANDOM_BIND, | 
|  251       base::Bind(&base::RandInt), |  185       base::Bind(&base::RandInt), | 
|  252       net_log_.net_log(), |  186       net_log_.net_log(), | 
|  253       net_log_.source())); |  187       net_log_.source())); | 
|  254  |  188  | 
|  255   net_log_.AddEvent( |  189   net_log_.AddEvent( | 
|  256       NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED, |  190       NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED, | 
|  257       make_scoped_refptr( |  191       make_scoped_refptr( | 
|  258           new DnsTransactionRetryParameters(attempts_, |  192           new DnsTransactionRetryParameters(attempts_, | 
|  259                                             socket_->NetLog().source()))); |  193                                             socket_->NetLog().source()))); | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
|  274                         query_->io_buffer()->size(), |  208                         query_->io_buffer()->size(), | 
|  275                         &io_callback_); |  209                         &io_callback_); | 
|  276 } |  210 } | 
|  277  |  211  | 
|  278 int DnsTransaction::DoSendQueryComplete(int rv) { |  212 int DnsTransaction::DoSendQueryComplete(int rv) { | 
|  279   if (rv < 0) |  213   if (rv < 0) | 
|  280     return rv; |  214     return rv; | 
|  281  |  215  | 
|  282   // Writing to UDP should not result in a partial datagram. |  216   // Writing to UDP should not result in a partial datagram. | 
|  283   if (rv != query_->io_buffer()->size()) |  217   if (rv != query_->io_buffer()->size()) | 
|  284     return ERR_NAME_NOT_RESOLVED; |  218     return ERR_MSG_TOO_BIG; | 
|  285  |  219  | 
|  286   next_state_ = STATE_READ_RESPONSE; |  220   next_state_ = STATE_READ_RESPONSE; | 
|  287   return OK; |  221   return OK; | 
|  288 } |  222 } | 
|  289  |  223  | 
|  290 int DnsTransaction::DoReadResponse() { |  224 int DnsTransaction::DoReadResponse() { | 
|  291   next_state_ = STATE_READ_RESPONSE_COMPLETE; |  225   next_state_ = STATE_READ_RESPONSE_COMPLETE; | 
|  292   response_.reset(new DnsResponse(query_.get())); |  226   response_.reset(new DnsResponse()); | 
|  293   return socket_->Read(response_->io_buffer(), |  227   return socket_->Read(response_->io_buffer(), | 
|  294                        response_->io_buffer()->size(), |  228                        response_->io_buffer()->size(), | 
|  295                        &io_callback_); |  229                        &io_callback_); | 
|  296 } |  230 } | 
|  297  |  231  | 
|  298 int DnsTransaction::DoReadResponseComplete(int rv) { |  232 int DnsTransaction::DoReadResponseComplete(int rv) { | 
|  299   DCHECK_NE(ERR_IO_PENDING, rv); |  233   DCHECK_NE(ERR_IO_PENDING, rv); | 
|  300   RevokeTimer(); |  234   RevokeTimer(); | 
|  301   if (rv < 0) |  235   if (rv < 0) | 
|  302     return rv; |  236     return rv; | 
|  303  |  237  | 
|  304   DCHECK(rv); |  238   DCHECK(rv); | 
|  305   // TODO(agayev): when supporting EDNS0 we may need to do multiple reads |  239   if (!response_->InitParse(rv, *query_)) | 
|  306   // to read the whole response. |  240     return ERR_DNS_MALFORMED_RESPONSE; | 
|  307   return response_->Parse(rv, &ip_addresses_); |  241   // TODO(szym): define this flag value in dns_protocol | 
 |  242   if (response_->flags1() & 2) | 
 |  243     return ERR_DNS_SERVER_REQUIRES_TCP; | 
 |  244   // TODO(szym): move this handling out of DnsTransaction? | 
 |  245   if (response_->rcode() != dns_protocol::kRcodeNOERROR && | 
 |  246       response_->rcode() != dns_protocol::kRcodeNXDOMAIN) { | 
 |  247     return ERR_DNS_SERVER_FAILED; | 
 |  248   } | 
 |  249   // TODO(szym): add ERR_DNS_RR_NOT_FOUND? | 
 |  250   if (response_->answer_count() == 0) | 
 |  251     return ERR_NAME_NOT_RESOLVED; | 
 |  252  | 
 |  253   return OK; | 
|  308 } |  254 } | 
|  309  |  255  | 
|  310 void DnsTransaction::StartTimer(base::TimeDelta delay) { |  256 void DnsTransaction::StartTimer(base::TimeDelta delay) { | 
|  311   timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout); |  257   timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout); | 
|  312 } |  258 } | 
|  313  |  259  | 
|  314 void DnsTransaction::RevokeTimer() { |  260 void DnsTransaction::RevokeTimer() { | 
|  315   timer_.Stop(); |  261   timer_.Stop(); | 
|  316 } |  262 } | 
|  317  |  263  | 
|  318 void DnsTransaction::OnTimeout() { |  264 void DnsTransaction::OnTimeout() { | 
|  319   DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || |  265   DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || | 
|  320          next_state_ == STATE_READ_RESPONSE_COMPLETE); |  266          next_state_ == STATE_READ_RESPONSE_COMPLETE); | 
|  321   if (attempts_ == timeouts_ms_.size()) { |  267   if (attempts_ == session_->config().attempts) { | 
|  322     DoCallback(ERR_DNS_TIMED_OUT); |  268     DoCallback(ERR_DNS_TIMED_OUT); | 
|  323     return; |  269     return; | 
|  324   } |  270   } | 
|  325   next_state_ = STATE_CONNECT; |  271   next_state_ = STATE_CONNECT; | 
|  326   query_.reset(query_->CloneWithNewId()); |  272   query_.reset(query_->CloneWithNewId(session_->NextId())); | 
|  327   int rv = DoLoop(OK); |  273   int rv = DoLoop(OK); | 
|  328   if (rv != ERR_IO_PENDING) |  274   if (rv != ERR_IO_PENDING) | 
|  329     DoCallback(rv); |  275     DoCallback(rv); | 
|  330 } |  276 } | 
|  331  |  277  | 
|  332 void DnsTransaction::set_timeouts_ms( |  | 
|  333     const std::vector<base::TimeDelta>& timeouts_ms) { |  | 
|  334   DCHECK_EQ(0u, attempts_); |  | 
|  335   timeouts_ms_ = timeouts_ms; |  | 
|  336 } |  | 
|  337  |  | 
|  338 }  // namespace net |  278 }  // namespace net | 
| OLD | NEW |