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" |
12 #include "base/strings/string_number_conversions.h" | |
10 #include "content/browser/renderer_host/p2p/socket_host_throttler.h" | 13 #include "content/browser/renderer_host/p2p/socket_host_throttler.h" |
11 #include "content/common/p2p_messages.h" | 14 #include "content/common/p2p_messages.h" |
12 #include "content/public/browser/content_browser_client.h" | 15 #include "content/public/browser/content_browser_client.h" |
13 #include "content/public/common/content_client.h" | 16 #include "content/public/common/content_client.h" |
14 #include "ipc/ipc_sender.h" | 17 #include "ipc/ipc_sender.h" |
15 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
16 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
17 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
18 #include "third_party/webrtc/base/asyncpacketsocket.h" | 21 #include "third_party/webrtc/base/asyncpacketsocket.h" |
19 | 22 |
(...skipping 17 matching lines...) Expand all Loading... | |
37 // This is caused by WSAENETRESET or WSAECONNRESET which means the | 40 // This is caused by WSAENETRESET or WSAECONNRESET which means the |
38 // last send resulted in an "ICMP Port Unreachable" message. | 41 // last send resulted in an "ICMP Port Unreachable" message. |
39 bool IsTransientError(int error) { | 42 bool IsTransientError(int error) { |
40 return error == net::ERR_ADDRESS_UNREACHABLE || | 43 return error == net::ERR_ADDRESS_UNREACHABLE || |
41 error == net::ERR_ADDRESS_INVALID || | 44 error == net::ERR_ADDRESS_INVALID || |
42 error == net::ERR_ACCESS_DENIED || | 45 error == net::ERR_ACCESS_DENIED || |
43 error == net::ERR_CONNECTION_RESET || | 46 error == net::ERR_CONNECTION_RESET || |
44 error == net::ERR_OUT_OF_MEMORY || | 47 error == net::ERR_OUT_OF_MEMORY || |
45 error == net::ERR_INTERNET_DISCONNECTED; | 48 error == net::ERR_INTERNET_DISCONNECTED; |
46 } | 49 } |
47 | |
Alexei Svitkine (slow)
2014/11/07 22:40:19
Nit: Don't remove an empty line here.
| |
48 } // namespace | 50 } // namespace |
49 | 51 |
50 namespace content { | 52 namespace content { |
51 | 53 |
52 P2PSocketHostUdp::PendingPacket::PendingPacket( | 54 P2PSocketHostUdp::PendingPacket::PendingPacket( |
53 const net::IPEndPoint& to, | 55 const net::IPEndPoint& to, |
54 const std::vector<char>& content, | 56 const std::vector<char>& content, |
55 const rtc::PacketOptions& options, | 57 const rtc::PacketOptions& options, |
56 uint64 id) | 58 uint64 id) |
57 : to(to), | 59 : to(to), |
(...skipping 19 matching lines...) Expand all Loading... | |
77 throttler_(throttler) { | 79 throttler_(throttler) { |
78 } | 80 } |
79 | 81 |
80 P2PSocketHostUdp::~P2PSocketHostUdp() { | 82 P2PSocketHostUdp::~P2PSocketHostUdp() { |
81 if (state_ == STATE_OPEN) { | 83 if (state_ == STATE_OPEN) { |
82 DCHECK(socket_.get()); | 84 DCHECK(socket_.get()); |
83 socket_.reset(); | 85 socket_.reset(); |
84 } | 86 } |
85 } | 87 } |
86 | 88 |
89 void P2PSocketHostUdp::SetSendBufferSize() { | |
90 unsigned int send_buffer_size = 0; | |
91 | |
92 if (base::StringToUint( | |
93 base::FieldTrialList::FindFullName("WebRTC-SystemUDPSendSocketSize"), | |
94 &send_buffer_size) && | |
95 send_buffer_size > 0) { | |
96 if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size)) { | |
97 LOG(WARNING) << "Failed to set socket send buffer size to " | |
98 << send_buffer_size; | |
99 } | |
100 } | |
101 } | |
102 | |
87 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, | 103 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, |
88 const P2PHostAndIPEndPoint& remote_address) { | 104 const P2PHostAndIPEndPoint& remote_address) { |
89 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 105 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
90 | 106 |
91 int result = socket_->Listen(local_address); | 107 int result = socket_->Listen(local_address); |
92 if (result < 0) { | 108 if (result < 0) { |
93 LOG(ERROR) << "bind() failed: " << result; | 109 LOG(ERROR) << "bind() failed: " << result; |
94 OnError(); | 110 OnError(); |
95 return false; | 111 return false; |
96 } | 112 } |
97 | 113 |
98 // Setting recv socket buffer size. | 114 // Setting recv socket buffer size. |
99 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { | 115 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { |
100 LOG(WARNING) << "Failed to set socket receive buffer size to " | 116 LOG(WARNING) << "Failed to set socket receive buffer size to " |
101 << kRecvSocketBufferSize; | 117 << kRecvSocketBufferSize; |
102 } | 118 } |
103 | 119 |
104 net::IPEndPoint address; | 120 net::IPEndPoint address; |
105 result = socket_->GetLocalAddress(&address); | 121 result = socket_->GetLocalAddress(&address); |
106 if (result < 0) { | 122 if (result < 0) { |
107 LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: " | 123 LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: " |
108 << result; | 124 << result; |
109 OnError(); | 125 OnError(); |
110 return false; | 126 return false; |
111 } | 127 } |
112 VLOG(1) << "Local address: " << address.ToString(); | 128 VLOG(1) << "Local address: " << address.ToString(); |
113 | 129 |
114 state_ = STATE_OPEN; | 130 state_ = STATE_OPEN; |
115 | 131 |
132 SetSendBufferSize(); | |
133 | |
116 // NOTE: Remote address will be same as what renderer provided. | 134 // NOTE: Remote address will be same as what renderer provided. |
117 message_sender_->Send(new P2PMsg_OnSocketCreated( | 135 message_sender_->Send(new P2PMsg_OnSocketCreated( |
118 id_, address, remote_address.ip_address)); | 136 id_, address, remote_address.ip_address)); |
119 | 137 |
120 recv_buffer_ = new net::IOBuffer(kReadBufferSize); | 138 recv_buffer_ = new net::IOBuffer(kReadBufferSize); |
121 DoRead(); | 139 DoRead(); |
122 | 140 |
123 return true; | 141 return true; |
124 } | 142 } |
125 | 143 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 int result = socket_->SetDiffServCodePoint(dscp); | 256 int result = socket_->SetDiffServCodePoint(dscp); |
239 if (result == net::OK) { | 257 if (result == net::OK) { |
240 last_dscp_ = dscp; | 258 last_dscp_ = dscp; |
241 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { | 259 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { |
242 // We receieved a non-transient error, and it seems we have | 260 // We receieved a non-transient error, and it seems we have |
243 // not changed the DSCP in the past, disable DSCP as it unlikely | 261 // not changed the DSCP in the past, disable DSCP as it unlikely |
244 // to work in the future. | 262 // to work in the future. |
245 last_dscp_ = net::DSCP_NO_CHANGE; | 263 last_dscp_ = net::DSCP_NO_CHANGE; |
246 } | 264 } |
247 } | 265 } |
266 | |
267 uint64 tick_received = base::TimeTicks::Now().ToInternalValue(); | |
268 | |
248 packet_processing_helpers::ApplyPacketOptions( | 269 packet_processing_helpers::ApplyPacketOptions( |
249 packet.data->data(), packet.size, packet.packet_options, 0); | 270 packet.data->data(), packet.size, packet.packet_options, 0); |
250 int result = socket_->SendTo( | 271 int result = socket_->SendTo(packet.data.get(), |
251 packet.data.get(), | 272 packet.size, |
252 packet.size, | 273 packet.to, |
253 packet.to, | 274 base::Bind(&P2PSocketHostUdp::OnSend, |
254 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id)); | 275 base::Unretained(this), |
276 packet.id, | |
277 tick_received)); | |
255 | 278 |
256 // sendto() may return an error, e.g. if we've received an ICMP Destination | 279 // 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, | 280 // Unreachable message. When this happens try sending the same packet again, |
258 // and just drop it if it fails again. | 281 // and just drop it if it fails again. |
259 if (IsTransientError(result)) { | 282 if (IsTransientError(result)) { |
260 result = socket_->SendTo( | 283 result = socket_->SendTo(packet.data.get(), |
261 packet.data.get(), | 284 packet.size, |
262 packet.size, | 285 packet.to, |
263 packet.to, | 286 base::Bind(&P2PSocketHostUdp::OnSend, |
264 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), | 287 base::Unretained(this), |
265 packet.id)); | 288 packet.id, |
289 tick_received)); | |
266 } | 290 } |
267 | 291 |
268 if (result == net::ERR_IO_PENDING) { | 292 if (result == net::ERR_IO_PENDING) { |
269 send_pending_ = true; | 293 send_pending_ = true; |
270 } else { | 294 } else { |
271 HandleSendResult(packet.id, result); | 295 HandleSendResult(packet.id, tick_received, result); |
272 } | 296 } |
273 | 297 |
274 if (dump_outgoing_rtp_packet_) | 298 if (dump_outgoing_rtp_packet_) |
275 DumpRtpPacket(packet.data->data(), packet.size, false); | 299 DumpRtpPacket(packet.data->data(), packet.size, false); |
276 } | 300 } |
277 | 301 |
278 void P2PSocketHostUdp::OnSend(uint64 packet_id, int result) { | 302 void P2PSocketHostUdp::OnSend(uint64 packet_id, |
303 uint64 tick_received, | |
304 int result) { | |
279 DCHECK(send_pending_); | 305 DCHECK(send_pending_); |
306 | |
Alexei Svitkine (slow)
2014/11/07 22:40:19
Nit: Looks like you add an extra new line here. Pl
| |
280 DCHECK_NE(result, net::ERR_IO_PENDING); | 307 DCHECK_NE(result, net::ERR_IO_PENDING); |
281 | 308 |
282 send_pending_ = false; | 309 send_pending_ = false; |
283 | 310 |
284 HandleSendResult(packet_id, result); | 311 HandleSendResult(packet_id, tick_received, result); |
285 | 312 |
286 // Send next packets if we have them waiting in the buffer. | 313 // Send next packets if we have them waiting in the buffer. |
287 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { | 314 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { |
288 PendingPacket packet = send_queue_.front(); | 315 PendingPacket packet = send_queue_.front(); |
289 DoSend(packet); | 316 DoSend(packet); |
290 send_queue_.pop_front(); | 317 send_queue_.pop_front(); |
291 DecrementDelayedBytes(packet.size); | 318 DecrementDelayedBytes(packet.size); |
292 } | 319 } |
293 } | 320 } |
294 | 321 |
295 void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, int result) { | 322 void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, |
323 uint64 tick_received, | |
324 int result) { | |
296 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, | 325 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, |
297 "result", result); | 326 "result", result); |
298 if (result < 0) { | 327 if (result < 0) { |
299 if (!IsTransientError(result)) { | 328 if (!IsTransientError(result)) { |
300 LOG(ERROR) << "Error when sending data in UDP socket: " << result; | 329 LOG(ERROR) << "Error when sending data in UDP socket: " << result; |
301 OnError(); | 330 OnError(); |
302 return; | 331 return; |
303 } | 332 } |
304 VLOG(0) << "sendto() has failed twice returning a " | 333 VLOG(0) << "sendto() has failed twice returning a " |
305 " transient error. Dropping the packet."; | 334 " transient error. Dropping the packet."; |
306 } | 335 } |
336 | |
337 // UMA to track the histograms from 1ms to 1 sec for how long a packet spends | |
338 // in the browser process. | |
339 UMA_HISTOGRAM_TIMES( | |
340 "WebRTC.SystemSendPacketDuration_UDP" /* name */, | |
341 base::TimeTicks::Now() - | |
342 base::TimeTicks::FromInternalValue(tick_received) /* sample */); | |
343 | |
307 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); | 344 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); |
308 } | 345 } |
309 | 346 |
310 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( | 347 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( |
311 const net::IPEndPoint& remote_address, int id) { | 348 const net::IPEndPoint& remote_address, int id) { |
312 NOTREACHED(); | 349 NOTREACHED(); |
313 OnError(); | 350 OnError(); |
314 return NULL; | 351 return NULL; |
315 } | 352 } |
316 | 353 |
317 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { | 354 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { |
318 DCHECK_EQ(STATE_OPEN, state_); | 355 DCHECK_EQ(STATE_OPEN, state_); |
319 switch (option) { | 356 switch (option) { |
320 case P2P_SOCKET_OPT_RCVBUF: | 357 case P2P_SOCKET_OPT_RCVBUF: |
321 return socket_->SetReceiveBufferSize(value) == net::OK; | 358 return socket_->SetReceiveBufferSize(value) == net::OK; |
322 case P2P_SOCKET_OPT_SNDBUF: | 359 case P2P_SOCKET_OPT_SNDBUF: |
323 return socket_->SetSendBufferSize(value) == net::OK; | 360 return socket_->SetSendBufferSize(value) == net::OK; |
324 case P2P_SOCKET_OPT_DSCP: | 361 case P2P_SOCKET_OPT_DSCP: |
325 return (net::OK == socket_->SetDiffServCodePoint( | 362 return (net::OK == socket_->SetDiffServCodePoint( |
326 static_cast<net::DiffServCodePoint>(value))) ? true : false; | 363 static_cast<net::DiffServCodePoint>(value))) ? true : false; |
327 default: | 364 default: |
328 NOTREACHED(); | 365 NOTREACHED(); |
329 return false; | 366 return false; |
330 } | 367 } |
331 } | 368 } |
332 | 369 |
333 } // namespace content | 370 } // namespace content |
OLD | NEW |