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

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

Issue 9190031: DnsClient refactoring + features (timeout, suffix search, server rotation). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added comments. Fixed tests. Created 8 years, 11 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/dns/dns_transaction.h"
6
7 #include "base/bind.h"
8 #include "base/rand_util.h"
9 #include "base/values.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/dns/dns_protocol.h"
13 #include "net/dns/dns_query.h"
14 #include "net/dns/dns_response.h"
15 #include "net/dns/dns_session.h"
16 #include "net/socket/client_socket_factory.h"
17 #include "net/udp/datagram_client_socket.h"
18
19 namespace net {
20
21 namespace {
22
23 class DnsTransactionStartParameters : public NetLog::EventParameters {
24 public:
25 DnsTransactionStartParameters(const IPEndPoint& dns_server,
26 const base::StringPiece& qname,
27 uint16 qtype,
28 const NetLog::Source& source)
29 : dns_server_(dns_server),
30 qname_(qname.data(), qname.length()),
31 qtype_(qtype),
32 source_(source) {}
33
34 virtual Value* ToValue() const {
35 DictionaryValue* dict = new DictionaryValue();
36 dict->SetString("dns_server", dns_server_.ToString());
37 dict->SetString("hostname", qname_);
38 dict->SetInteger("query_type", qtype_);
39 if (source_.is_valid())
40 dict->Set("source_dependency", source_.ToValue());
41 return dict;
42 }
43
44 private:
45 IPEndPoint dns_server_;
46 std::string qname_;
47 uint16 qtype_;
48 const NetLog::Source source_;
49 };
50
51 class DnsTransactionFinishParameters : public NetLog::EventParameters {
52 public:
53 // TODO(szym): add rcode ?
54 DnsTransactionFinishParameters(int net_error, int answer_count)
55 : net_error_(net_error), answer_count_(answer_count) {}
56
57 virtual Value* ToValue() const {
58 DictionaryValue* dict = new DictionaryValue();
59 if (net_error_)
60 dict->SetInteger("net_error", net_error_);
61 dict->SetInteger("answer_count", answer_count_);
62 return dict;
63 }
64
65 private:
66 const int net_error_;
67 const int answer_count_;
68 };
69
70 class DnsTransactionRetryParameters : public NetLog::EventParameters {
71 public:
72 DnsTransactionRetryParameters(int attempt_number,
73 const NetLog::Source& source)
74 : attempt_number_(attempt_number), source_(source) {}
75
76 virtual Value* ToValue() const {
77 DictionaryValue* dict = new DictionaryValue();
78 dict->SetInteger("attempt_number", attempt_number_);
79 dict->Set("source_dependency", source_.ToValue());
80 return dict;
81 }
82
83 private:
84 const int attempt_number_;
85 const NetLog::Source source_;
86 };
87
88 } // namespace
89
90
91 DnsTransaction::DnsTransaction(DnsSession* session,
92 const base::StringPiece& qname,
93 uint16 qtype,
94 const ResultCallback& callback,
95 const BoundNetLog& source_net_log)
96 : session_(session),
97 dns_server_(session->NextServer()),
98 query_(new DnsQuery(session->NextId(), qname, qtype)),
99 callback_(callback),
100 attempts_(0),
101 next_state_(STATE_NONE),
102 net_log_(BoundNetLog::Make(session->net_log(),
103 NetLog::SOURCE_DNS_TRANSACTION)) {
104 net_log_.BeginEvent(
105 NetLog::TYPE_DNS_TRANSACTION,
106 make_scoped_refptr(
107 new DnsTransactionStartParameters(dns_server_,
108 qname,
109 qtype,
110 source_net_log.source())));
111 }
112
113 DnsTransaction::~DnsTransaction() {}
114
115 int DnsTransaction::Start() {
116 DCHECK_EQ(STATE_NONE, next_state_);
117 next_state_ = STATE_CONNECT;
118 return DoLoop(OK);
119 }
120
121 int DnsTransaction::DoLoop(int result) {
122 DCHECK_NE(STATE_NONE, next_state_);
123 int rv = result;
124 do {
125 State state = next_state_;
126 next_state_ = STATE_NONE;
127 switch (state) {
128 case STATE_CONNECT:
129 rv = DoConnect();
130 break;
131 case STATE_CONNECT_COMPLETE:
132 rv = DoConnectComplete(rv);
133 break;
134 case STATE_SEND_QUERY:
135 rv = DoSendQuery();
136 break;
137 case STATE_SEND_QUERY_COMPLETE:
138 rv = DoSendQueryComplete(rv);
139 break;
140 case STATE_READ_RESPONSE:
141 rv = DoReadResponse();
142 break;
143 case STATE_READ_RESPONSE_COMPLETE:
144 rv = DoReadResponseComplete(rv);
145 break;
146 default:
147 NOTREACHED();
148 break;
149 }
150 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
151
152 return rv;
153 }
154
155 void DnsTransaction::DoCallback(int result) {
156 DCHECK_NE(result, ERR_IO_PENDING);
157 int answer_count = (result == OK) ? response()->answer_count() : 0;
158 net_log_.EndEvent(
159 NetLog::TYPE_DNS_TRANSACTION,
160 make_scoped_refptr(
161 new DnsTransactionFinishParameters(result, answer_count)));
162 callback_.Run(this, result);
163 }
164
165 void DnsTransaction::OnIOComplete(int result) {
166 int rv = DoLoop(result);
167 if (rv != ERR_IO_PENDING)
168 DoCallback(rv);
169 }
170
171 int DnsTransaction::DoConnect() {
172 next_state_ = STATE_CONNECT_COMPLETE;
173
174 StartTimer(session_->NextTimeout(attempts_));
175 ++attempts_;
176
177 // TODO(szym): keep all sockets around in case the server responds
178 // after its timeout; state machine will need to change to handle that.
179 // The current plan is to move socket management out to DnsSession.
180 // Hence also move retransmissions to DnsClient::Request.
181 socket_.reset(session_->socket_factory()->CreateDatagramClientSocket(
182 DatagramSocket::RANDOM_BIND,
183 base::Bind(&base::RandInt),
184 net_log_.net_log(),
185 net_log_.source()));
186
187 net_log_.AddEvent(
188 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED,
189 make_scoped_refptr(
190 new DnsTransactionRetryParameters(attempts_,
191 socket_->NetLog().source())));
192
193 return socket_->Connect(dns_server_);
194 }
195
196 int DnsTransaction::DoConnectComplete(int rv) {
197 if (rv < 0)
198 return rv;
199 next_state_ = STATE_SEND_QUERY;
200 return OK;
201 }
202
203 int DnsTransaction::DoSendQuery() {
204 next_state_ = STATE_SEND_QUERY_COMPLETE;
205 return socket_->Write(query_->io_buffer(),
206 query_->io_buffer()->size(),
207 base::Bind(&DnsTransaction::OnIOComplete,
208 base::Unretained(this)));
209 }
210
211 int DnsTransaction::DoSendQueryComplete(int rv) {
212 if (rv < 0)
213 return rv;
214
215 // Writing to UDP should not result in a partial datagram.
216 if (rv != query_->io_buffer()->size())
217 return ERR_MSG_TOO_BIG;
218
219 next_state_ = STATE_READ_RESPONSE;
220 return OK;
221 }
222
223 int DnsTransaction::DoReadResponse() {
224 next_state_ = STATE_READ_RESPONSE_COMPLETE;
225 response_.reset(new DnsResponse());
226 return socket_->Read(response_->io_buffer(),
227 response_->io_buffer()->size(),
228 base::Bind(&DnsTransaction::OnIOComplete,
229 base::Unretained(this)));
230 }
231
232 int DnsTransaction::DoReadResponseComplete(int rv) {
233 DCHECK_NE(ERR_IO_PENDING, rv);
234 RevokeTimer();
235 if (rv < 0)
236 return rv;
237
238 DCHECK(rv);
239 if (!response_->InitParse(rv, *query_))
240 return ERR_DNS_MALFORMED_RESPONSE;
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;
254 }
255
256 void DnsTransaction::StartTimer(base::TimeDelta delay) {
257 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout);
258 }
259
260 void DnsTransaction::RevokeTimer() {
261 timer_.Stop();
262 }
263
264 void DnsTransaction::OnTimeout() {
265 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE ||
266 next_state_ == STATE_READ_RESPONSE_COMPLETE);
267 if (attempts_ == session_->config().attempts) {
268 DoCallback(ERR_DNS_TIMED_OUT);
269 return;
270 }
271 next_state_ = STATE_CONNECT;
272 query_.reset(query_->CloneWithNewId(session_->NextId()));
273 int rv = DoLoop(OK);
274 if (rv != ERR_IO_PENDING)
275 DoCallback(rv);
276 }
277
278 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698