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 "content/browser/renderer_host/p2p/socket_host_udp.h" | 5 #include "content/browser/renderer_host/p2p/socket_host_udp.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/metrics/field_trial.h" | |
10 #include "base/metrics/histogram.h" | |
9 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
10 #include "content/browser/renderer_host/p2p/socket_host_throttler.h" | 12 #include "content/browser/renderer_host/p2p/socket_host_throttler.h" |
11 #include "content/common/p2p_messages.h" | 13 #include "content/common/p2p_messages.h" |
12 #include "content/public/browser/content_browser_client.h" | 14 #include "content/public/browser/content_browser_client.h" |
13 #include "content/public/common/content_client.h" | 15 #include "content/public/common/content_client.h" |
14 #include "ipc/ipc_sender.h" | 16 #include "ipc/ipc_sender.h" |
15 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
16 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
17 #include "net/base/net_util.h" | 19 #include "net/base/net_util.h" |
18 #include "third_party/webrtc/base/asyncpacketsocket.h" | 20 #include "third_party/webrtc/base/asyncpacketsocket.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 | 69 |
68 P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender, | 70 P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender, |
69 int socket_id, | 71 int socket_id, |
70 P2PMessageThrottler* throttler) | 72 P2PMessageThrottler* throttler) |
71 : P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP), | 73 : P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP), |
72 socket_( | 74 socket_( |
73 new net::UDPServerSocket(GetContentClient()->browser()->GetNetLog(), | 75 new net::UDPServerSocket(GetContentClient()->browser()->GetNetLog(), |
74 net::NetLog::Source())), | 76 net::NetLog::Source())), |
75 send_pending_(false), | 77 send_pending_(false), |
76 last_dscp_(net::DSCP_CS0), | 78 last_dscp_(net::DSCP_CS0), |
79 random_socket_id_prefix_(0), | |
77 throttler_(throttler) { | 80 throttler_(throttler) { |
78 } | 81 } |
79 | 82 |
80 P2PSocketHostUdp::~P2PSocketHostUdp() { | 83 P2PSocketHostUdp::~P2PSocketHostUdp() { |
81 if (state_ == STATE_OPEN) { | 84 if (state_ == STATE_OPEN) { |
82 DCHECK(socket_.get()); | 85 DCHECK(socket_.get()); |
83 socket_.reset(); | 86 socket_.reset(); |
84 } | 87 } |
85 } | 88 } |
86 | 89 |
90 void P2PSocketHostUdp::SetSendBufferSize() { | |
91 int send_buffer_size = 0; | |
92 if (base::FieldTrialList::FindFullName("WebRTC-SystemUDPSendSocketSize") == | |
juberti2
2014/11/04 06:00:18
Seems like we should read FindFullName into a stri
Alexei Svitkine (slow)
2014/11/04 15:17:50
Agreed.
guoweis2
2014/11/07 22:18:19
Done.
| |
93 "2K") { | |
94 send_buffer_size = 2048; | |
95 } else if (base::FieldTrialList::FindFullName( | |
96 "WebRTC-SystemUDPSendSocketSize") == "64K") { | |
Alexei Svitkine (slow)
2014/11/04 15:17:50
I would normally suggest to use variation params h
guoweis2
2014/11/07 22:18:19
Variation is not allowed so following the pattern
| |
97 send_buffer_size = 65536; | |
98 } else if (base::FieldTrialList::FindFullName( | |
99 "WebRTC-SystemUDPSendSocketSize") == "256K") { | |
100 send_buffer_size = 262144; | |
Alexei Svitkine (slow)
2014/11/04 15:17:50
Nit: It would be more readable to have these be 25
guoweis2
2014/11/07 22:18:19
Done.
| |
101 } | |
102 | |
103 if (send_buffer_size > 0) { | |
juberti2
2014/11/04 06:00:18
Probably want to invalidate the experiment if this
guoweis2
2014/11/07 22:18:19
Alexei, is there a way to invalidate this instance
| |
104 // Setting send socket buffer size. | |
105 if (socket_->SetSendBufferSize(send_buffer_size) != net::OK) { | |
106 LOG(WARNING) << "Failed to set socket send buffer size to " | |
107 << send_buffer_size; | |
108 } | |
109 } | |
110 } | |
111 | |
87 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, | 112 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, |
88 const P2PHostAndIPEndPoint& remote_address) { | 113 const P2PHostAndIPEndPoint& remote_address) { |
89 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 114 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
90 | 115 |
91 int result = socket_->Listen(local_address); | 116 int result = socket_->Listen(local_address); |
92 if (result < 0) { | 117 if (result < 0) { |
93 LOG(ERROR) << "bind() failed: " << result; | 118 LOG(ERROR) << "bind() failed: " << result; |
94 OnError(); | 119 OnError(); |
95 return false; | 120 return false; |
96 } | 121 } |
97 | 122 |
98 // Setting recv socket buffer size. | 123 // Setting recv socket buffer size. |
99 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { | 124 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { |
100 LOG(WARNING) << "Failed to set socket receive buffer size to " | 125 LOG(WARNING) << "Failed to set socket receive buffer size to " |
101 << kRecvSocketBufferSize; | 126 << kRecvSocketBufferSize; |
102 } | 127 } |
103 | 128 |
129 SetSendBufferSize(); | |
130 | |
104 net::IPEndPoint address; | 131 net::IPEndPoint address; |
105 result = socket_->GetLocalAddress(&address); | 132 result = socket_->GetLocalAddress(&address); |
106 if (result < 0) { | 133 if (result < 0) { |
107 LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: " | 134 LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: " |
108 << result; | 135 << result; |
109 OnError(); | 136 OnError(); |
110 return false; | 137 return false; |
111 } | 138 } |
112 VLOG(1) << "Local address: " << address.ToString(); | 139 VLOG(1) << "Local address: " << address.ToString(); |
113 | 140 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
187 void P2PSocketHostUdp::Send(const net::IPEndPoint& to, | 214 void P2PSocketHostUdp::Send(const net::IPEndPoint& to, |
188 const std::vector<char>& data, | 215 const std::vector<char>& data, |
189 const rtc::PacketOptions& options, | 216 const rtc::PacketOptions& options, |
190 uint64 packet_id) { | 217 uint64 packet_id) { |
191 if (!socket_) { | 218 if (!socket_) { |
192 // The Send message may be sent after the an OnError message was | 219 // The Send message may be sent after the an OnError message was |
193 // sent by hasn't been processed the renderer. | 220 // sent by hasn't been processed the renderer. |
194 return; | 221 return; |
195 } | 222 } |
196 | 223 |
224 // The lower 32 bits of packet id is a sequence number. 2^32 bits is a large | |
225 // number space. If we send 1000 packets per second, it'll take 49 days to | |
226 // finish 2^32 bits. | |
227 if (random_socket_id_prefix_ == 0) { | |
228 random_socket_id_prefix_ = (packet_id >> 32) << 32; | |
229 } else { | |
230 DCHECK_EQ((random_socket_id_prefix_ >> 32), (packet_id >> 32)); | |
231 } | |
232 | |
197 if (!ContainsKey(connected_peers_, to)) { | 233 if (!ContainsKey(connected_peers_, to)) { |
198 P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType(); | 234 P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType(); |
199 bool stun = GetStunPacketType(&*data.begin(), data.size(), &type); | 235 bool stun = GetStunPacketType(&*data.begin(), data.size(), &type); |
200 if (!stun || type == STUN_DATA_INDICATION) { | 236 if (!stun || type == STUN_DATA_INDICATION) { |
201 LOG(ERROR) << "Page tried to send a data packet to " << to.ToString() | 237 LOG(ERROR) << "Page tried to send a data packet to " << to.ToString() |
202 << " before STUN binding is finished."; | 238 << " before STUN binding is finished."; |
203 OnError(); | 239 OnError(); |
204 return; | 240 return; |
205 } | 241 } |
206 | 242 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 int result = socket_->SetDiffServCodePoint(dscp); | 274 int result = socket_->SetDiffServCodePoint(dscp); |
239 if (result == net::OK) { | 275 if (result == net::OK) { |
240 last_dscp_ = dscp; | 276 last_dscp_ = dscp; |
241 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { | 277 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { |
242 // We receieved a non-transient error, and it seems we have | 278 // We receieved a non-transient error, and it seems we have |
243 // not changed the DSCP in the past, disable DSCP as it unlikely | 279 // not changed the DSCP in the past, disable DSCP as it unlikely |
244 // to work in the future. | 280 // to work in the future. |
245 last_dscp_ = net::DSCP_NO_CHANGE; | 281 last_dscp_ = net::DSCP_NO_CHANGE; |
246 } | 282 } |
247 } | 283 } |
284 | |
285 uint64 call_record = | |
juberti2
2014/11/04 06:00:18
For the future, I think it would be better to allo
guoweis2
2014/11/07 22:18:19
Changed to allocate memory.
| |
286 PackCallRecord(packet.id, base::TimeTicks::Now().ToInternalValue()); | |
287 | |
248 packet_processing_helpers::ApplyPacketOptions( | 288 packet_processing_helpers::ApplyPacketOptions( |
249 packet.data->data(), packet.size, packet.packet_options, 0); | 289 packet.data->data(), packet.size, packet.packet_options, 0); |
250 int result = socket_->SendTo( | 290 int result = socket_->SendTo( |
251 packet.data.get(), | 291 packet.data.get(), |
252 packet.size, | 292 packet.size, |
253 packet.to, | 293 packet.to, |
254 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id)); | 294 base::Bind( |
295 &P2PSocketHostUdp::OnSend, base::Unretained(this), call_record)); | |
255 | 296 |
256 // sendto() may return an error, e.g. if we've received an ICMP Destination | 297 // sendto() may return an error, e.g. if we've received an ICMP Destination |
257 // Unreachable message. When this happens try sending the same packet again, | 298 // Unreachable message. When this happens try sending the same packet again, |
258 // and just drop it if it fails again. | 299 // and just drop it if it fails again. |
259 if (IsTransientError(result)) { | 300 if (IsTransientError(result)) { |
260 result = socket_->SendTo( | 301 result = socket_->SendTo( |
261 packet.data.get(), | 302 packet.data.get(), |
262 packet.size, | 303 packet.size, |
263 packet.to, | 304 packet.to, |
264 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), | 305 base::Bind( |
265 packet.id)); | 306 &P2PSocketHostUdp::OnSend, base::Unretained(this), call_record)); |
266 } | 307 } |
267 | 308 |
268 if (result == net::ERR_IO_PENDING) { | 309 if (result == net::ERR_IO_PENDING) { |
269 send_pending_ = true; | 310 send_pending_ = true; |
270 } else { | 311 } else { |
271 HandleSendResult(packet.id, result); | 312 HandleSendResult(call_record, result); |
272 } | 313 } |
273 | 314 |
274 if (dump_outgoing_rtp_packet_) | 315 if (dump_outgoing_rtp_packet_) |
275 DumpRtpPacket(packet.data->data(), packet.size, false); | 316 DumpRtpPacket(packet.data->data(), packet.size, false); |
276 } | 317 } |
277 | 318 |
278 void P2PSocketHostUdp::OnSend(uint64 packet_id, int result) { | 319 void P2PSocketHostUdp::OnSend(uint64 call_record, int result) { |
279 DCHECK(send_pending_); | 320 DCHECK(send_pending_); |
321 | |
280 DCHECK_NE(result, net::ERR_IO_PENDING); | 322 DCHECK_NE(result, net::ERR_IO_PENDING); |
281 | 323 |
282 send_pending_ = false; | 324 send_pending_ = false; |
283 | 325 |
284 HandleSendResult(packet_id, result); | 326 HandleSendResult(call_record, result); |
285 | 327 |
286 // Send next packets if we have them waiting in the buffer. | 328 // Send next packets if we have them waiting in the buffer. |
287 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { | 329 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { |
288 PendingPacket packet = send_queue_.front(); | 330 PendingPacket packet = send_queue_.front(); |
289 DoSend(packet); | 331 DoSend(packet); |
290 send_queue_.pop_front(); | 332 send_queue_.pop_front(); |
291 DecrementDelayedBytes(packet.size); | 333 DecrementDelayedBytes(packet.size); |
292 } | 334 } |
293 } | 335 } |
294 | 336 |
295 void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, int result) { | 337 void P2PSocketHostUdp::HandleSendResult(uint64 call_record, int result) { |
338 uint64 packet_id; | |
339 uint64 ticks; | |
340 UnpackCallRecord(call_record, | |
341 random_socket_id_prefix_, | |
342 base::TimeTicks::Now().ToInternalValue(), | |
343 &packet_id, | |
344 &ticks); | |
345 | |
296 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, | 346 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, |
297 "result", result); | 347 "result", result); |
298 if (result < 0) { | 348 if (result < 0) { |
299 if (!IsTransientError(result)) { | 349 if (!IsTransientError(result)) { |
300 LOG(ERROR) << "Error when sending data in UDP socket: " << result; | 350 LOG(ERROR) << "Error when sending data in UDP socket: " << result; |
301 OnError(); | 351 OnError(); |
302 return; | 352 return; |
303 } | 353 } |
304 VLOG(0) << "sendto() has failed twice returning a " | 354 VLOG(0) << "sendto() has failed twice returning a " |
305 " transient error. Dropping the packet."; | 355 " transient error. Dropping the packet."; |
306 } | 356 } |
357 | |
358 // UMA to track the histograms from 1ms to 1 sec for how long a packet spends | |
359 // in the browser process. | |
360 UMA_HISTOGRAM_CUSTOM_TIMES( | |
361 "WebRTC.SystemSendPacketDuration_UDP" /* name */, | |
362 base::TimeDelta::FromInternalValue(ticks) /* sample */, | |
363 base::TimeDelta::FromMilliseconds(1) /* min */, | |
364 base::TimeDelta::FromSeconds(1) /* max */, | |
365 100 /* bucket_count */); | |
Alexei Svitkine (slow)
2014/11/04 15:17:50
I suggest just using UMA_HISTOGRAM_TIMES() here, w
guoweis2
2014/11/07 22:18:19
Done.
| |
366 | |
307 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); | 367 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); |
308 } | 368 } |
309 | 369 |
310 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( | 370 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( |
311 const net::IPEndPoint& remote_address, int id) { | 371 const net::IPEndPoint& remote_address, int id) { |
312 NOTREACHED(); | 372 NOTREACHED(); |
313 OnError(); | 373 OnError(); |
314 return NULL; | 374 return NULL; |
315 } | 375 } |
316 | 376 |
317 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { | 377 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { |
318 DCHECK_EQ(STATE_OPEN, state_); | 378 DCHECK_EQ(STATE_OPEN, state_); |
319 switch (option) { | 379 switch (option) { |
320 case P2P_SOCKET_OPT_RCVBUF: | 380 case P2P_SOCKET_OPT_RCVBUF: |
321 return socket_->SetReceiveBufferSize(value) == net::OK; | 381 return socket_->SetReceiveBufferSize(value) == net::OK; |
322 case P2P_SOCKET_OPT_SNDBUF: | 382 case P2P_SOCKET_OPT_SNDBUF: |
323 return socket_->SetSendBufferSize(value) == net::OK; | 383 return socket_->SetSendBufferSize(value) == net::OK; |
324 case P2P_SOCKET_OPT_DSCP: | 384 case P2P_SOCKET_OPT_DSCP: |
325 return (net::OK == socket_->SetDiffServCodePoint( | 385 return (net::OK == socket_->SetDiffServCodePoint( |
326 static_cast<net::DiffServCodePoint>(value))) ? true : false; | 386 static_cast<net::DiffServCodePoint>(value))) ? true : false; |
327 default: | 387 default: |
328 NOTREACHED(); | 388 NOTREACHED(); |
329 return false; | 389 return false; |
330 } | 390 } |
331 } | 391 } |
332 | 392 |
393 #define ALL_ONES_LOWER_32_BITS ((1uLL << 32) - 1) | |
394 | |
395 uint64 P2PSocketHostUdp::PackCallRecord(const uint64 packet_id, | |
396 const uint64 ticks_now) { | |
397 // Lower 32 bits is the packet id. | |
398 uint64 call_record = packet_id & ALL_ONES_LOWER_32_BITS; | |
399 uint64 ticks_now_lower = ticks_now & ALL_ONES_LOWER_32_BITS; | |
400 return (ticks_now_lower << 32) + call_record; | |
401 } | |
402 | |
403 void P2PSocketHostUdp::UnpackCallRecord(const uint64 packed_call_record, | |
404 const uint64 random_socket_id_prefix, | |
405 const uint64 ticks_now, | |
406 uint64* packet_id, | |
407 uint64* ticks_diff) { | |
408 // Prefix the random prefix to the packet id. | |
409 *packet_id = | |
410 (packed_call_record & ALL_ONES_LOWER_32_BITS) | random_socket_id_prefix; | |
411 | |
412 // Calculate the tick spent. | |
413 int64 ticks_duration = | |
414 (ticks_now & ALL_ONES_LOWER_32_BITS) - (packed_call_record >> 32); | |
415 | |
416 if (ticks_duration < 0) { | |
417 ticks_duration = ALL_ONES_LOWER_32_BITS + ticks_duration + 1; | |
418 } | |
419 *ticks_diff = ticks_duration; | |
420 } | |
421 | |
333 } // namespace content | 422 } // namespace content |
OLD | NEW |