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

Side by Side Diff: chrome/browser/net/network_stats.cc

Issue 7056031: Collect stats to investigate the viability of UDP (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 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 "chrome/browser/net/network_stats.h"
6
7 #include "base/callback_old.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/task.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time.h"
15 #include "base/tuple.h"
16 #include "content/browser/browser_thread.h"
17 #include "net/base/address_list.h"
18 #include "net/base/host_resolver.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/net_util.h"
21 #include "net/base/sys_addrinfo.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/socket/tcp_client_socket.h"
24 #include "net/udp/udp_client_socket.h"
25 #include "net/udp/udp_server_socket.h"
26
27 namespace chrome_browser_net {
28
29 // NetworkStats methods and members.
30 NetworkStats::NetworkStats()
31 : socket_(NULL),
32 errors_(0),
33 bytes_to_read_(0),
34 bytes_to_send_(0),
35 ALLOW_THIS_IN_INITIALIZER_LIST(
36 read_callback_(this, &NetworkStats::OnReadComplete)),
37 ALLOW_THIS_IN_INITIALIZER_LIST(
38 write_callback_(this, &NetworkStats::OnWriteComplete)),
39 finished_callback_(NULL),
40 start_time_(base::TimeTicks::Now()) {
41 }
42
43 NetworkStats::~NetworkStats() {
44 socket_ = NULL;
45 }
46
47 void NetworkStats::OnReadComplete(int result) {
48 if (result <= 0) {
49 errors_++;
50 this->Finish(READ_FAIL, result);
51 return;
52 }
53
54 if (!received_stream_.VerifyBytes(read_buffer_->data(), result)) {
55 errors_++;
56 this->Finish(READ_VERIFY_FAIL, result);
57 return;
58 }
59
60 bytes_to_read_ -= result;
61
62 // Now read more data...
63 if (bytes_to_read_)
64 this->ReadData();
65 else
66 this->Finish(SUCCESS, net::OK);
67 }
68
69 void NetworkStats::OnWriteComplete(int result) {
70 if (result <= 0) {
71 errors_++;
72 this->Finish(WRITE_FAIL, result);
73 return;
74 }
75
76 write_buffer_->DidConsume(result);
77 bytes_to_send_ -= result;
78 if (!write_buffer_->BytesRemaining())
79 write_buffer_ = NULL;
80
81 if (bytes_to_send_)
82 this->SendData();
83 }
84
85 void NetworkStats::ReadData() {
86 DCHECK(!read_buffer_.get());
87 read_buffer_ = new net::IOBuffer(kMaxMessage);
88
89 int rv;
90 do {
91 rv = socket_->Read(read_buffer_, kMaxMessage, &read_callback_);
92 if (rv == net::ERR_IO_PENDING)
93 return;
94 this->OnReadComplete(rv); // Complete the read manually.
95 } while (rv > 0);
96
97 read_buffer_ = NULL;
98 }
99
100 void NetworkStats::SendData() {
101 DCHECK(bytes_to_send_); // We should have data to send.
102 const int kWriteChunkSize = 777; // 777 is more abusive.
Mike Belshe 2011/05/27 21:27:00 Do you need this chunking? I had that in the unit
ramant (doing other things) 2011/05/31 21:25:36 Done.
103
104 do {
105 if (!write_buffer_.get()) {
106 int bytes_to_send = std::min(kWriteChunkSize, bytes_to_send_);
107 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(bytes_to_send));
108 sent_stream_.GetBytes(buffer->data(), bytes_to_send);
109 write_buffer_ = new net::DrainableIOBuffer(buffer, bytes_to_send);
110 }
111
112 int rv = socket_->Write(write_buffer_,
113 write_buffer_->BytesRemaining(),
114 &write_callback_);
115 if (rv == net::ERR_IO_PENDING)
116 return;
117
Mike Belshe 2011/05/27 21:27:00 rv could be <0, indicating an error. It should be
ramant (doing other things) 2011/05/31 21:25:36 Done.
118 write_buffer_->DidConsume(rv);
119 bytes_to_send_ -= rv;
120 if (!write_buffer_->BytesRemaining())
121 write_buffer_ = NULL;
122 } while (bytes_to_send_);
123 }
124
125 // UDPStatsClient methods and members.
126 UDPStatsClient::UDPStatsClient()
127 : NetworkStats() {
128 }
129
130 UDPStatsClient::~UDPStatsClient() {
131 socket_ = NULL;
132 }
133
134 bool UDPStatsClient::Start(const std::string& ip_str,
135 int port,
136 int bytes_to_send,
137 net::CompletionCallback* callback) {
138 DCHECK(!socket_);
139 DCHECK(port);
140 DCHECK(bytes_to_send); // We should have data to send.
141
142 finished_callback_ = callback;
143 bytes_to_read_ = bytes_to_send_ = bytes_to_send;
Mike Belshe 2011/05/27 21:27:00 nit: I think these compound assignments are again
ramant (doing other things) 2011/05/31 21:25:36 Done.
144
145 net::IPAddressNumber ip_number;
146 if (!net::ParseIPLiteralToNumber(ip_str, &ip_number)) {
147 errors_++;
148 this->Finish(IP_STRING_PARSE_FAIL, net::ERR_INVALID_ARGUMENT);
Mike Belshe 2011/05/27 21:27:00 nit: generally we don't do 'this->' in our code.
ramant (doing other things) 2011/05/31 21:25:36 Done.
149 return false;
150 }
151
152 net::IPEndPoint server_address = net::IPEndPoint(ip_number, port);
153
154 net::UDPClientSocket* socket =
155 new net::UDPClientSocket(NULL, net::NetLog::Source());
156
157 int rv = socket->Connect(server_address);
158 if (rv < 0) {
159 errors_++;
160 this->Finish(CONNECT_FAIL, rv);
161 return false;
162 }
163
164 socket_ = socket;
165
166 start_time_ = base::TimeTicks::Now();
167 this->SendData();
Mike Belshe 2011/05/27 21:27:00 I think you'll need: if (SendData() < 0) { Fin
ramant (doing other things) 2011/05/31 21:25:36 Done.
168
169 this->ReadData();
170
171 return true;
172 }
173
174
175 void UDPStatsClient::Finish(Status status, int result) {
176 base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
177 if (result == net::OK) {
178 UMA_HISTOGRAM_TIMES("NetConnectivity.UDP.SuccessRTT", duration);
179 } else {
180 UMA_HISTOGRAM_TIMES("NetConnectivity.UDP.FailRTT", duration);
181 }
182
183 UMA_HISTOGRAM_ENUMERATION("NetConnectivity.UDP.Status", status, STATUS_MAX);
184
185 if (finished_callback_ != NULL) {
186 net::CompletionCallback* callback = finished_callback_;
187 finished_callback_ = NULL;
188 callback->Run(result);
189 }
190 }
191
192 // TCPStatsClient methods and members.
193 TCPStatsClient::TCPStatsClient()
194 : NetworkStats(),
195 ALLOW_THIS_IN_INITIALIZER_LIST(
196 connect_callback_(this, &TCPStatsClient::OnConnectComplete)) {
197 }
198
199 TCPStatsClient::~TCPStatsClient() {
200 if (socket_) {
201 net::TCPClientSocket* socket = static_cast<net::TCPClientSocket*>(socket_);
202 socket->Disconnect();
203 socket_ = NULL;
204 }
205 }
206
207 bool TCPStatsClient::Start(const net::HostPortPair& server_host_port_pair,
208 int bytes_to_send,
209 net::CompletionCallback* callback) {
210 DCHECK(!socket_);
211 DCHECK(bytes_to_send); // We should have data to send.
212
213 finished_callback_ = callback;
214 bytes_to_read_ = bytes_to_send_ = bytes_to_send;
215
216 scoped_ptr<net::HostResolver> system_host_resolver(
217 net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
218 net::HostResolver::kDefaultRetryAttempts,
219 NULL));
220 net::SingleRequestHostResolver host_resolver(system_host_resolver.get());
221 net::HostResolver::RequestInfo request(server_host_port_pair);
222 net::AddressList addresses;
223 int rv = host_resolver.Resolve(request, &addresses, NULL, net::BoundNetLog());
224 if (rv != net::OK) {
225 errors_++;
226 this->Finish(RESOLVE_FAIL, rv);
227 return false;
228 }
229
230 net::TCPClientSocket* socket =
231 new net::TCPClientSocket(addresses, NULL, net::NetLog::Source());
232 socket_ = socket;
233 rv = socket->Connect(&connect_callback_);
234 if (rv == net::ERR_IO_PENDING)
235 return true;
236 OnConnectComplete(rv);
237 return rv == net::OK;
238 }
239
240 void TCPStatsClient::OnConnectComplete(int result) {
241 if (result < 0) {
242 errors_++;
243 this->Finish(CONNECT_FAIL, result);
244 return;
245 }
246
247 DCHECK(bytes_to_send_); // We should have data to send.
248
249 start_time_ = base::TimeTicks::Now();
250
251 this->SendData();
Mike Belshe 2011/05/27 21:27:00 Same concern about Send() failing here.
ramant (doing other things) 2011/05/31 21:25:36 Done.
252
253 this->ReadData();
254 }
255
256 void TCPStatsClient::Finish(Status status, int result) {
257 base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
258 if (result == net::OK) {
259 UMA_HISTOGRAM_TIMES("NetConnectivity.TCP.SuccessRTT", duration);
260 } else {
261 UMA_HISTOGRAM_TIMES("NetConnectivity.TCP.FailRTT", duration);
262 }
263
264 UMA_HISTOGRAM_ENUMERATION("NetConnectivity.TCP.Status", status, STATUS_MAX);
265
266 if (finished_callback_ != NULL) {
267 net::CompletionCallback* callback = finished_callback_;
268 finished_callback_ = NULL;
269 callback->Run(result);
270 }
271 }
272
273 // static
274 void CollectNetworkStats(const std::string& network_stats_server) {
275 if (network_stats_server.empty())
276 return;
277 // If we are not on IO Thread, then post a task to call CollectNetworkStats on
278 // IO Thread.
279 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
280 BrowserThread::PostTask(
281 BrowserThread::IO,
282 FROM_HERE,
283 NewRunnableFunction(&CollectNetworkStats, network_stats_server));
284 return;
285 }
286
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
288
289 static scoped_refptr<base::FieldTrial> trial = NULL;
290 static bool collect_stats = false;
291
292 if (!trial.get()) {
293 // Set up a field trial to collect network stats for UDP and TCP.
294 base::FieldTrial::Probability kDivisor = 1000;
295
296 // Enable the connectivity testing for 0.1% of the users.
297 base::FieldTrial::Probability kProbabilityPerGroup = 1;
298
299 // After October 30, 2011 builds, it will always be in default group
300 // (disable_network_stats).
301 trial = new base::FieldTrial("NetworkConnectivity", kDivisor,
302 "disable_network_stats", 2011, 10, 30);
303
304 // Add option to collect_stats for NetworkConnectivity.
305 int collect_stats_group = trial->AppendGroup("collect_stats",
306 kProbabilityPerGroup);
307 if (trial->group() == collect_stats_group)
308 collect_stats = true;
309 }
310
Mike Belshe 2011/05/27 21:27:00 Is there a way to add a check to see if the networ
ramant (doing other things) 2011/05/31 21:25:36 UMA calls only after it has successfully uploaded
311 if (collect_stats) {
312 TCPStatsClient* tcp_stats_client = new TCPStatsClient();
313 net::HostPortPair server_address(network_stats_server, 80);
314 tcp_stats_client->Start(server_address, 5, NULL);
Mike Belshe 2011/06/03 18:25:32 One last thing - what do you think of doing a smal
ramant (doing other things) 2011/06/05 17:54:13 Done.
315
316 UDPStatsClient* udp_stats_client = new UDPStatsClient();
317 udp_stats_client->Start(network_stats_server, 90, 5, NULL);
Mike Belshe 2011/05/27 21:27:00 Port 90 is an IANA registered port for dnsix. ht
ramant (doing other things) 2011/05/31 21:25:36 Done.
318 }
319 }
320
321 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698