| 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 13 matching lines...) Expand all  Loading... | 
|   24 #include "net/base/completion_callback.h" |   24 #include "net/base/completion_callback.h" | 
|   25 #include "net/base/dns_util.h" |   25 #include "net/base/dns_util.h" | 
|   26 #include "net/base/io_buffer.h" |   26 #include "net/base/io_buffer.h" | 
|   27 #include "net/base/ip_endpoint.h" |   27 #include "net/base/ip_endpoint.h" | 
|   28 #include "net/base/net_errors.h" |   28 #include "net/base/net_errors.h" | 
|   29 #include "net/base/net_log.h" |   29 #include "net/base/net_log.h" | 
|   30 #include "net/dns/dns_protocol.h" |   30 #include "net/dns/dns_protocol.h" | 
|   31 #include "net/dns/dns_query.h" |   31 #include "net/dns/dns_query.h" | 
|   32 #include "net/dns/dns_response.h" |   32 #include "net/dns/dns_response.h" | 
|   33 #include "net/dns/dns_session.h" |   33 #include "net/dns/dns_session.h" | 
|   34 #include "net/socket/client_socket_factory.h" |  | 
|   35 #include "net/udp/datagram_client_socket.h" |   34 #include "net/udp/datagram_client_socket.h" | 
|   36  |   35  | 
|   37 namespace net { |   36 namespace net { | 
|   38  |   37  | 
|   39 namespace { |   38 namespace { | 
|   40  |   39  | 
|   41 // Provide a common macro to simplify code and readability. We must use a |   40 // Provide a common macro to simplify code and readability. We must use a | 
|   42 // macro as the underlying HISTOGRAM macro creates static variables. |   41 // macro as the underlying HISTOGRAM macro creates static variables. | 
|   43 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ |   42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ | 
|   44     base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) |   43     base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|   65   return dict; |   64   return dict; | 
|   66 }; |   65 }; | 
|   67  |   66  | 
|   68 // ---------------------------------------------------------------------------- |   67 // ---------------------------------------------------------------------------- | 
|   69  |   68  | 
|   70 // A single asynchronous DNS exchange over UDP, which consists of sending out a |   69 // A single asynchronous DNS exchange over UDP, which consists of sending out a | 
|   71 // DNS query, waiting for a response, and returning the response that it |   70 // DNS query, waiting for a response, and returning the response that it | 
|   72 // matches. Logging is done in the socket and in the outer DnsTransaction. |   71 // matches. Logging is done in the socket and in the outer DnsTransaction. | 
|   73 class DnsUDPAttempt { |   72 class DnsUDPAttempt { | 
|   74  public: |   73  public: | 
|   75   DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, |   74   DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, | 
|   76                 const IPEndPoint& server, |  | 
|   77                 scoped_ptr<DnsQuery> query, |   75                 scoped_ptr<DnsQuery> query, | 
|   78                 const CompletionCallback& callback) |   76                 const CompletionCallback& callback) | 
|   79       : next_state_(STATE_NONE), |   77       : next_state_(STATE_NONE), | 
|   80         received_malformed_response_(false), |   78         received_malformed_response_(false), | 
|   81         socket_(socket.Pass()), |   79         socket_lease_(socket_lease.Pass()), | 
|   82         server_(server), |  | 
|   83         query_(query.Pass()), |   80         query_(query.Pass()), | 
|   84         callback_(callback) { |   81         callback_(callback) { | 
|   85   } |   82   } | 
|   86  |   83  | 
|   87   // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously |   84   // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | 
|   88   // and calls |callback| upon completion. |   85   // and calls |callback| upon completion. | 
|   89   int Start() { |   86   int Start() { | 
|   90     DCHECK_EQ(STATE_NONE, next_state_); |   87     DCHECK_EQ(STATE_NONE, next_state_); | 
|   91     int rv = socket_->Connect(server_); |  | 
|   92     DCHECK_NE(ERR_IO_PENDING, rv); |  | 
|   93     if (rv < 0) |  | 
|   94       return rv; |  | 
|   95     start_time_ = base::TimeTicks::Now(); |   88     start_time_ = base::TimeTicks::Now(); | 
|   96     next_state_ = STATE_SEND_QUERY; |   89     next_state_ = STATE_SEND_QUERY; | 
|   97     return DoLoop(OK); |   90     return DoLoop(OK); | 
|   98   } |   91   } | 
|   99  |   92  | 
|  100   const DnsQuery* query() const { |   93   const DnsQuery* query() const { | 
|  101     return query_.get(); |   94     return query_.get(); | 
|  102   } |   95   } | 
|  103  |   96  | 
|  104   const DatagramClientSocket* socket() const { |   97   const BoundNetLog& socket_net_log() const { | 
|  105     return socket_.get(); |   98     return socket_lease_->socket()->NetLog(); | 
|  106   } |   99   } | 
|  107  |  100  | 
|  108   // Returns the response or NULL if has not received a matching response from |  101   // Returns the response or NULL if has not received a matching response from | 
|  109   // the server. |  102   // the server. | 
|  110   const DnsResponse* response() const { |  103   const DnsResponse* response() const { | 
|  111     const DnsResponse* resp = response_.get(); |  104     const DnsResponse* resp = response_.get(); | 
|  112     return (resp != NULL && resp->IsValid()) ? resp : NULL; |  105     return (resp != NULL && resp->IsValid()) ? resp : NULL; | 
|  113   } |  106   } | 
|  114  |  107  | 
|  115   // Returns a Value representing the received response, along with a reference |  108   // Returns a Value representing the received response, along with a reference | 
|  116   // to the NetLog source source of the UDP socket used.  The request must have |  109   // to the NetLog source source of the UDP socket used.  The request must have | 
|  117   // completed before this is called. |  110   // completed before this is called. | 
|  118   Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { |  111   Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { | 
|  119     DCHECK(response_->IsValid()); |  112     DCHECK(response_->IsValid()); | 
|  120  |  113  | 
|  121     DictionaryValue* dict = new DictionaryValue(); |  114     DictionaryValue* dict = new DictionaryValue(); | 
|  122     dict->SetInteger("rcode", response_->rcode()); |  115     dict->SetInteger("rcode", response_->rcode()); | 
|  123     dict->SetInteger("answer_count", response_->answer_count()); |  116     dict->SetInteger("answer_count", response_->answer_count()); | 
|  124     socket_->NetLog().source().AddToEventParameters(dict); |  117     socket_net_log().source().AddToEventParameters(dict); | 
|  125     return dict; |  118     return dict; | 
|  126   } |  119   } | 
|  127  |  120  | 
|  128  private: |  121  private: | 
|  129   enum State { |  122   enum State { | 
|  130     STATE_SEND_QUERY, |  123     STATE_SEND_QUERY, | 
|  131     STATE_SEND_QUERY_COMPLETE, |  124     STATE_SEND_QUERY_COMPLETE, | 
|  132     STATE_READ_RESPONSE, |  125     STATE_READ_RESPONSE, | 
|  133     STATE_READ_RESPONSE_COMPLETE, |  126     STATE_READ_RESPONSE_COMPLETE, | 
|  134     STATE_NONE, |  127     STATE_NONE, | 
|  135   }; |  128   }; | 
|  136  |  129  | 
 |  130   DatagramClientSocket* socket() { | 
 |  131     return socket_lease_->socket(); | 
 |  132   } | 
 |  133  | 
|  137   int DoLoop(int result) { |  134   int DoLoop(int result) { | 
|  138     CHECK_NE(STATE_NONE, next_state_); |  135     CHECK_NE(STATE_NONE, next_state_); | 
|  139     int rv = result; |  136     int rv = result; | 
|  140     do { |  137     do { | 
|  141       State state = next_state_; |  138       State state = next_state_; | 
|  142       next_state_ = STATE_NONE; |  139       next_state_ = STATE_NONE; | 
|  143       switch (state) { |  140       switch (state) { | 
|  144         case STATE_SEND_QUERY: |  141         case STATE_SEND_QUERY: | 
|  145           rv = DoSendQuery(); |  142           rv = DoSendQuery(); | 
|  146           break; |  143           break; | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  167                     base::TimeTicks::Now() - start_time_); |  164                     base::TimeTicks::Now() - start_time_); | 
|  168     } else if (rv != ERR_IO_PENDING) { |  165     } else if (rv != ERR_IO_PENDING) { | 
|  169       DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", |  166       DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", | 
|  170                     base::TimeTicks::Now() - start_time_); |  167                     base::TimeTicks::Now() - start_time_); | 
|  171     } |  168     } | 
|  172     return rv; |  169     return rv; | 
|  173   } |  170   } | 
|  174  |  171  | 
|  175   int DoSendQuery() { |  172   int DoSendQuery() { | 
|  176     next_state_ = STATE_SEND_QUERY_COMPLETE; |  173     next_state_ = STATE_SEND_QUERY_COMPLETE; | 
|  177     return socket_->Write(query_->io_buffer(), |  174     return socket()->Write(query_->io_buffer(), | 
|  178                           query_->io_buffer()->size(), |  175                               query_->io_buffer()->size(), | 
|  179                           base::Bind(&DnsUDPAttempt::OnIOComplete, |  176                               base::Bind(&DnsUDPAttempt::OnIOComplete, | 
|  180                                      base::Unretained(this))); |  177                                          base::Unretained(this))); | 
|  181   } |  178   } | 
|  182  |  179  | 
|  183   int DoSendQueryComplete(int rv) { |  180   int DoSendQueryComplete(int rv) { | 
|  184     DCHECK_NE(ERR_IO_PENDING, rv); |  181     DCHECK_NE(ERR_IO_PENDING, rv); | 
|  185     if (rv < 0) |  182     if (rv < 0) | 
|  186       return rv; |  183       return rv; | 
|  187  |  184  | 
|  188     // Writing to UDP should not result in a partial datagram. |  185     // Writing to UDP should not result in a partial datagram. | 
|  189     if (rv != query_->io_buffer()->size()) |  186     if (rv != query_->io_buffer()->size()) | 
|  190       return ERR_MSG_TOO_BIG; |  187       return ERR_MSG_TOO_BIG; | 
|  191  |  188  | 
|  192     next_state_ = STATE_READ_RESPONSE; |  189     next_state_ = STATE_READ_RESPONSE; | 
|  193     return OK; |  190     return OK; | 
|  194   } |  191   } | 
|  195  |  192  | 
|  196   int DoReadResponse() { |  193   int DoReadResponse() { | 
|  197     next_state_ = STATE_READ_RESPONSE_COMPLETE; |  194     next_state_ = STATE_READ_RESPONSE_COMPLETE; | 
|  198     response_.reset(new DnsResponse()); |  195     response_.reset(new DnsResponse()); | 
|  199     return socket_->Read(response_->io_buffer(), |  196     return socket()->Read(response_->io_buffer(), | 
|  200                          response_->io_buffer()->size(), |  197                              response_->io_buffer()->size(), | 
|  201                          base::Bind(&DnsUDPAttempt::OnIOComplete, |  198                              base::Bind(&DnsUDPAttempt::OnIOComplete, | 
|  202                                     base::Unretained(this))); |  199                                         base::Unretained(this))); | 
|  203   } |  200   } | 
|  204  |  201  | 
|  205   int DoReadResponseComplete(int rv) { |  202   int DoReadResponseComplete(int rv) { | 
|  206     DCHECK_NE(ERR_IO_PENDING, rv); |  203     DCHECK_NE(ERR_IO_PENDING, rv); | 
|  207     if (rv < 0) |  204     if (rv < 0) | 
|  208       return rv; |  205       return rv; | 
|  209  |  206  | 
|  210     DCHECK(rv); |  207     DCHECK(rv); | 
|  211     if (!response_->InitParse(rv, *query_)) { |  208     if (!response_->InitParse(rv, *query_)) { | 
|  212       // Other implementations simply ignore mismatched responses. Since each |  209       // Other implementations simply ignore mismatched responses. Since each | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  233   void OnIOComplete(int rv) { |  230   void OnIOComplete(int rv) { | 
|  234     rv = DoLoop(rv); |  231     rv = DoLoop(rv); | 
|  235     if (rv != ERR_IO_PENDING) |  232     if (rv != ERR_IO_PENDING) | 
|  236       callback_.Run(rv); |  233       callback_.Run(rv); | 
|  237   } |  234   } | 
|  238  |  235  | 
|  239   State next_state_; |  236   State next_state_; | 
|  240   bool received_malformed_response_; |  237   bool received_malformed_response_; | 
|  241   base::TimeTicks start_time_; |  238   base::TimeTicks start_time_; | 
|  242  |  239  | 
|  243   scoped_ptr<DatagramClientSocket> socket_; |  240   scoped_ptr<DnsSession::SocketLease> socket_lease_; | 
|  244   IPEndPoint server_; |  | 
|  245   scoped_ptr<DnsQuery> query_; |  241   scoped_ptr<DnsQuery> query_; | 
|  246  |  242  | 
|  247   scoped_ptr<DnsResponse> response_; |  243   scoped_ptr<DnsResponse> response_; | 
|  248  |  244  | 
|  249   CompletionCallback callback_; |  245   CompletionCallback callback_; | 
|  250  |  246  | 
|  251   DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); |  247   DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 
|  252 }; |  248 }; | 
|  253  |  249  | 
|  254 // ---------------------------------------------------------------------------- |  250 // ---------------------------------------------------------------------------- | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  394  |  390  | 
|  395     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); |  391     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); | 
|  396     callback.Run(this, result.rv, response); |  392     callback.Run(this, result.rv, response); | 
|  397   } |  393   } | 
|  398  |  394  | 
|  399   // Makes another attempt at the current name, |qnames_.front()|, using the |  395   // Makes another attempt at the current name, |qnames_.front()|, using the | 
|  400   // next nameserver. |  396   // next nameserver. | 
|  401   AttemptResult MakeAttempt() { |  397   AttemptResult MakeAttempt() { | 
|  402     unsigned attempt_number = attempts_.size(); |  398     unsigned attempt_number = attempts_.size(); | 
|  403  |  399  | 
|  404 #if defined(OS_WIN) |  | 
|  405     // Avoid the Windows firewall warning about explicit UDP binding. |  | 
|  406     // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413 |  | 
|  407     DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND; |  | 
|  408 #else |  | 
|  409     DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND; |  | 
|  410 #endif |  | 
|  411  |  | 
|  412     scoped_ptr<DatagramClientSocket> socket( |  | 
|  413         session_->socket_factory()->CreateDatagramClientSocket( |  | 
|  414             bind_type, |  | 
|  415             base::Bind(&base::RandInt), |  | 
|  416             net_log_.net_log(), |  | 
|  417             net_log_.source())); |  | 
|  418  |  | 
|  419     uint16 id = session_->NextQueryId(); |  400     uint16 id = session_->NextQueryId(); | 
|  420     scoped_ptr<DnsQuery> query; |  401     scoped_ptr<DnsQuery> query; | 
|  421     if (attempts_.empty()) { |  402     if (attempts_.empty()) { | 
|  422       query.reset(new DnsQuery(id, qnames_.front(), qtype_)); |  403       query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | 
|  423     } else { |  404     } else { | 
|  424       query.reset(attempts_[0]->query()->CloneWithNewId(id)); |  405       query.reset(attempts_[0]->query()->CloneWithNewId(id)); | 
|  425     } |  406     } | 
|  426  |  407  | 
|  427     net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, |  | 
|  428                       socket->NetLog().source().ToEventParametersCallback()); |  | 
|  429  |  | 
|  430     const DnsConfig& config = session_->config(); |  408     const DnsConfig& config = session_->config(); | 
|  431  |  409  | 
|  432     unsigned server_index = first_server_index_ + |  410     unsigned server_index = first_server_index_ + | 
|  433         (attempt_number % config.nameservers.size()); |  411         (attempt_number % config.nameservers.size()); | 
|  434  |  412  | 
 |  413     scoped_ptr<DnsSession::SocketLease> lease = | 
 |  414         session_->AllocateSocket(server_index, net_log_.source()); | 
 |  415  | 
 |  416     bool got_socket = !!lease.get(); | 
 |  417  | 
|  435     DnsUDPAttempt* attempt = new DnsUDPAttempt( |  418     DnsUDPAttempt* attempt = new DnsUDPAttempt( | 
|  436         socket.Pass(), |  419         lease.Pass(), | 
|  437         config.nameservers[server_index], |  | 
|  438         query.Pass(), |  420         query.Pass(), | 
|  439         base::Bind(&DnsTransactionImpl::OnAttemptComplete, |  421         base::Bind(&DnsTransactionImpl::OnAttemptComplete, | 
|  440                    base::Unretained(this), |  422                    base::Unretained(this), | 
|  441                    attempt_number)); |  423                    attempt_number)); | 
|  442  |  424  | 
|  443     attempts_.push_back(attempt); |  425     attempts_.push_back(attempt); | 
|  444  |  426  | 
 |  427     if (!got_socket) | 
 |  428       return AttemptResult(ERR_CONNECTION_REFUSED, NULL); | 
 |  429  | 
 |  430     net_log_.AddEvent( | 
 |  431         NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, | 
 |  432         attempt->socket_net_log().source().ToEventParametersCallback()); | 
 |  433  | 
|  445     int rv = attempt->Start(); |  434     int rv = attempt->Start(); | 
|  446     if (rv == ERR_IO_PENDING) { |  435     if (rv == ERR_IO_PENDING) { | 
|  447       timer_.Stop(); |  436       timer_.Stop(); | 
|  448       base::TimeDelta timeout = session_->NextTimeout(attempt_number); |  437       base::TimeDelta timeout = session_->NextTimeout(attempt_number); | 
|  449       timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); |  438       timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | 
|  450     } |  439     } | 
|  451     return AttemptResult(rv, attempt); |  440     return AttemptResult(rv, attempt); | 
|  452   } |  441   } | 
|  453  |  442  | 
|  454   // Begins query for the current name. Makes the first attempt. |  443   // Begins query for the current name. Makes the first attempt. | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  504           net_log_.EndEventWithNetErrorCode( |  493           net_log_.EndEventWithNetErrorCode( | 
|  505               NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); |  494               NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); | 
|  506           // Try next suffix. |  495           // Try next suffix. | 
|  507           qnames_.pop_front(); |  496           qnames_.pop_front(); | 
|  508           if (qnames_.empty()) { |  497           if (qnames_.empty()) { | 
|  509             return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); |  498             return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); | 
|  510           } else { |  499           } else { | 
|  511             result = StartQuery(); |  500             result = StartQuery(); | 
|  512           } |  501           } | 
|  513           break; |  502           break; | 
 |  503         case ERR_CONNECTION_REFUSED: | 
|  514         case ERR_DNS_TIMED_OUT: |  504         case ERR_DNS_TIMED_OUT: | 
|  515           if (MoreAttemptsAllowed()) { |  505           if (MoreAttemptsAllowed()) { | 
|  516             result = MakeAttempt(); |  506             result = MakeAttempt(); | 
|  517           } else { |  507           } else { | 
|  518             return result; |  508             return result; | 
|  519           } |  509           } | 
|  520           break; |  510           break; | 
|  521         default: |  511         default: | 
|  522           // Server failure. |  512           // Server failure. | 
|  523           DCHECK(result.attempt); |  513           DCHECK(result.attempt); | 
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  599 }  // namespace |  589 }  // namespace | 
|  600  |  590  | 
|  601 // static |  591 // static | 
|  602 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( |  592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 
|  603     DnsSession* session) { |  593     DnsSession* session) { | 
|  604   return scoped_ptr<DnsTransactionFactory>( |  594   return scoped_ptr<DnsTransactionFactory>( | 
|  605       new DnsTransactionFactoryImpl(session)); |  595       new DnsTransactionFactoryImpl(session)); | 
|  606 } |  596 } | 
|  607  |  597  | 
|  608 }  // namespace net |  598 }  // namespace net | 
| OLD | NEW |