Chromium Code Reviews| 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 18 matching lines...) Expand all Loading... | |
| 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 | 50 |
| 51 struct AsyncCallRecord { | |
| 52 AsyncCallRecord(uint64 packet_id, uint64 ticks_received) { | |
| 53 this->packet_id = packet_id; | |
| 54 this->ticks_received = ticks_received; | |
| 55 } | |
| 56 uint64 packet_id; | |
| 57 uint64 ticks_received; | |
| 58 }; | |
| 48 } // namespace | 59 } // namespace |
| 49 | 60 |
| 50 namespace content { | 61 namespace content { |
| 51 | 62 |
| 52 P2PSocketHostUdp::PendingPacket::PendingPacket( | 63 P2PSocketHostUdp::PendingPacket::PendingPacket( |
| 53 const net::IPEndPoint& to, | 64 const net::IPEndPoint& to, |
| 54 const std::vector<char>& content, | 65 const std::vector<char>& content, |
| 55 const rtc::PacketOptions& options, | 66 const rtc::PacketOptions& options, |
| 56 uint64 id) | 67 uint64 id) |
| 57 : to(to), | 68 : to(to), |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 77 throttler_(throttler) { | 88 throttler_(throttler) { |
| 78 } | 89 } |
| 79 | 90 |
| 80 P2PSocketHostUdp::~P2PSocketHostUdp() { | 91 P2PSocketHostUdp::~P2PSocketHostUdp() { |
| 81 if (state_ == STATE_OPEN) { | 92 if (state_ == STATE_OPEN) { |
| 82 DCHECK(socket_.get()); | 93 DCHECK(socket_.get()); |
| 83 socket_.reset(); | 94 socket_.reset(); |
| 84 } | 95 } |
| 85 } | 96 } |
| 86 | 97 |
| 98 void P2PSocketHostUdp::SetSendBufferSize() { | |
| 99 unsigned send_buffer_size = 0; | |
|
juberti2
2014/11/07 22:24:59
unsigned int
| |
| 100 | |
| 101 // In the finch experiment, groups will be named like "2K", "64K", | |
|
juberti2
2014/11/07 22:24:59
OOC, would it make more sense to just name the gro
| |
| 102 // etc. The StringToUint will convert the leading number part. | |
| 103 if (base::StringToUint( | |
| 104 base::FieldTrialList::FindFullName("WebRTC-SystemUDPSendSocketSize"), | |
| 105 &send_buffer_size) && | |
|
Alexei Svitkine (slow)
2014/11/07 22:24:35
I don't think checking the return value of this fu
| |
| 106 send_buffer_size > 0) { | |
| 107 if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size * 1024)) { | |
| 108 LOG(WARNING) << "Failed to set socket send buffer size to " | |
| 109 << send_buffer_size * 1024; | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 87 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, | 114 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address, |
| 88 const P2PHostAndIPEndPoint& remote_address) { | 115 const P2PHostAndIPEndPoint& remote_address) { |
| 89 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 116 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
| 90 | 117 |
| 91 int result = socket_->Listen(local_address); | 118 int result = socket_->Listen(local_address); |
| 92 if (result < 0) { | 119 if (result < 0) { |
| 93 LOG(ERROR) << "bind() failed: " << result; | 120 LOG(ERROR) << "bind() failed: " << result; |
| 94 OnError(); | 121 OnError(); |
| 95 return false; | 122 return false; |
| 96 } | 123 } |
| 97 | 124 |
| 98 // Setting recv socket buffer size. | 125 // Setting recv socket buffer size. |
| 99 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { | 126 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) { |
| 100 LOG(WARNING) << "Failed to set socket receive buffer size to " | 127 LOG(WARNING) << "Failed to set socket receive buffer size to " |
| 101 << kRecvSocketBufferSize; | 128 << kRecvSocketBufferSize; |
| 102 } | 129 } |
| 103 | 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 |
| 114 state_ = STATE_OPEN; | 141 state_ = STATE_OPEN; |
| 115 | 142 |
| 143 SetSendBufferSize(); | |
| 144 | |
| 116 // NOTE: Remote address will be same as what renderer provided. | 145 // NOTE: Remote address will be same as what renderer provided. |
| 117 message_sender_->Send(new P2PMsg_OnSocketCreated( | 146 message_sender_->Send(new P2PMsg_OnSocketCreated( |
| 118 id_, address, remote_address.ip_address)); | 147 id_, address, remote_address.ip_address)); |
| 119 | 148 |
| 120 recv_buffer_ = new net::IOBuffer(kReadBufferSize); | 149 recv_buffer_ = new net::IOBuffer(kReadBufferSize); |
| 121 DoRead(); | 150 DoRead(); |
| 122 | 151 |
| 123 return true; | 152 return true; |
| 124 } | 153 } |
| 125 | 154 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 int result = socket_->SetDiffServCodePoint(dscp); | 267 int result = socket_->SetDiffServCodePoint(dscp); |
| 239 if (result == net::OK) { | 268 if (result == net::OK) { |
| 240 last_dscp_ = dscp; | 269 last_dscp_ = dscp; |
| 241 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { | 270 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) { |
| 242 // We receieved a non-transient error, and it seems we have | 271 // We receieved a non-transient error, and it seems we have |
| 243 // not changed the DSCP in the past, disable DSCP as it unlikely | 272 // not changed the DSCP in the past, disable DSCP as it unlikely |
| 244 // to work in the future. | 273 // to work in the future. |
| 245 last_dscp_ = net::DSCP_NO_CHANGE; | 274 last_dscp_ = net::DSCP_NO_CHANGE; |
| 246 } | 275 } |
| 247 } | 276 } |
| 277 | |
| 278 uint64 call_record = reinterpret_cast<uint64>( | |
| 279 new AsyncCallRecord(packet.id, base::TimeTicks::Now().ToInternalValue())); | |
| 280 | |
| 248 packet_processing_helpers::ApplyPacketOptions( | 281 packet_processing_helpers::ApplyPacketOptions( |
| 249 packet.data->data(), packet.size, packet.packet_options, 0); | 282 packet.data->data(), packet.size, packet.packet_options, 0); |
| 250 int result = socket_->SendTo( | 283 int result = socket_->SendTo( |
| 251 packet.data.get(), | 284 packet.data.get(), |
| 252 packet.size, | 285 packet.size, |
| 253 packet.to, | 286 packet.to, |
| 254 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id)); | 287 base::Bind( |
| 288 &P2PSocketHostUdp::OnSend, base::Unretained(this), call_record)); | |
|
Alexei Svitkine (slow)
2014/11/07 22:24:35
I think you should be able to bind to the params d
| |
| 255 | 289 |
| 256 // sendto() may return an error, e.g. if we've received an ICMP Destination | 290 // 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, | 291 // Unreachable message. When this happens try sending the same packet again, |
| 258 // and just drop it if it fails again. | 292 // and just drop it if it fails again. |
| 259 if (IsTransientError(result)) { | 293 if (IsTransientError(result)) { |
| 260 result = socket_->SendTo( | 294 result = socket_->SendTo( |
| 261 packet.data.get(), | 295 packet.data.get(), |
| 262 packet.size, | 296 packet.size, |
| 263 packet.to, | 297 packet.to, |
| 264 base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), | 298 base::Bind( |
| 265 packet.id)); | 299 &P2PSocketHostUdp::OnSend, base::Unretained(this), call_record)); |
| 266 } | 300 } |
| 267 | 301 |
| 268 if (result == net::ERR_IO_PENDING) { | 302 if (result == net::ERR_IO_PENDING) { |
| 269 send_pending_ = true; | 303 send_pending_ = true; |
| 270 } else { | 304 } else { |
| 271 HandleSendResult(packet.id, result); | 305 HandleSendResult(call_record, result); |
| 272 } | 306 } |
| 273 | 307 |
| 274 if (dump_outgoing_rtp_packet_) | 308 if (dump_outgoing_rtp_packet_) |
| 275 DumpRtpPacket(packet.data->data(), packet.size, false); | 309 DumpRtpPacket(packet.data->data(), packet.size, false); |
| 276 } | 310 } |
| 277 | 311 |
| 278 void P2PSocketHostUdp::OnSend(uint64 packet_id, int result) { | 312 void P2PSocketHostUdp::OnSend(uint64 call_record, int result) { |
| 279 DCHECK(send_pending_); | 313 DCHECK(send_pending_); |
| 314 | |
| 280 DCHECK_NE(result, net::ERR_IO_PENDING); | 315 DCHECK_NE(result, net::ERR_IO_PENDING); |
| 281 | 316 |
| 282 send_pending_ = false; | 317 send_pending_ = false; |
| 283 | 318 |
| 284 HandleSendResult(packet_id, result); | 319 HandleSendResult(call_record, result); |
| 285 | 320 |
| 286 // Send next packets if we have them waiting in the buffer. | 321 // Send next packets if we have them waiting in the buffer. |
| 287 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { | 322 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { |
| 288 PendingPacket packet = send_queue_.front(); | 323 PendingPacket packet = send_queue_.front(); |
| 289 DoSend(packet); | 324 DoSend(packet); |
| 290 send_queue_.pop_front(); | 325 send_queue_.pop_front(); |
| 291 DecrementDelayedBytes(packet.size); | 326 DecrementDelayedBytes(packet.size); |
| 292 } | 327 } |
| 293 } | 328 } |
| 294 | 329 |
| 295 void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, int result) { | 330 void P2PSocketHostUdp::HandleSendResult(uint64 call_record, int result) { |
| 331 scoped_ptr<AsyncCallRecord> call_record_ptr( | |
| 332 reinterpret_cast<AsyncCallRecord*>(call_record)); | |
| 333 uint64 packet_id = call_record_ptr->packet_id; | |
| 334 uint64 ticks_received = call_record_ptr->ticks_received; | |
| 335 | |
| 296 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, | 336 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id, |
| 297 "result", result); | 337 "result", result); |
| 298 if (result < 0) { | 338 if (result < 0) { |
| 299 if (!IsTransientError(result)) { | 339 if (!IsTransientError(result)) { |
| 300 LOG(ERROR) << "Error when sending data in UDP socket: " << result; | 340 LOG(ERROR) << "Error when sending data in UDP socket: " << result; |
| 301 OnError(); | 341 OnError(); |
| 302 return; | 342 return; |
| 303 } | 343 } |
| 304 VLOG(0) << "sendto() has failed twice returning a " | 344 VLOG(0) << "sendto() has failed twice returning a " |
| 305 " transient error. Dropping the packet."; | 345 " transient error. Dropping the packet."; |
| 306 } | 346 } |
| 347 | |
| 348 // UMA to track the histograms from 1ms to 1 sec for how long a packet spends | |
| 349 // in the browser process. | |
| 350 UMA_HISTOGRAM_TIMES( | |
| 351 "WebRTC.SystemSendPacketDuration_UDP" /* name */, | |
| 352 base::TimeTicks::Now() - | |
| 353 base::TimeTicks::FromInternalValue(ticks_received) /* sample */); | |
| 354 | |
| 307 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); | 355 message_sender_->Send(new P2PMsg_OnSendComplete(id_)); |
| 308 } | 356 } |
| 309 | 357 |
| 310 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( | 358 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection( |
| 311 const net::IPEndPoint& remote_address, int id) { | 359 const net::IPEndPoint& remote_address, int id) { |
| 312 NOTREACHED(); | 360 NOTREACHED(); |
| 313 OnError(); | 361 OnError(); |
| 314 return NULL; | 362 return NULL; |
| 315 } | 363 } |
| 316 | 364 |
| 317 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { | 365 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) { |
| 318 DCHECK_EQ(STATE_OPEN, state_); | 366 DCHECK_EQ(STATE_OPEN, state_); |
| 319 switch (option) { | 367 switch (option) { |
| 320 case P2P_SOCKET_OPT_RCVBUF: | 368 case P2P_SOCKET_OPT_RCVBUF: |
| 321 return socket_->SetReceiveBufferSize(value) == net::OK; | 369 return socket_->SetReceiveBufferSize(value) == net::OK; |
| 322 case P2P_SOCKET_OPT_SNDBUF: | 370 case P2P_SOCKET_OPT_SNDBUF: |
| 323 return socket_->SetSendBufferSize(value) == net::OK; | 371 return socket_->SetSendBufferSize(value) == net::OK; |
| 324 case P2P_SOCKET_OPT_DSCP: | 372 case P2P_SOCKET_OPT_DSCP: |
| 325 return (net::OK == socket_->SetDiffServCodePoint( | 373 return (net::OK == socket_->SetDiffServCodePoint( |
| 326 static_cast<net::DiffServCodePoint>(value))) ? true : false; | 374 static_cast<net::DiffServCodePoint>(value))) ? true : false; |
| 327 default: | 375 default: |
| 328 NOTREACHED(); | 376 NOTREACHED(); |
| 329 return false; | 377 return false; |
| 330 } | 378 } |
| 331 } | 379 } |
| 332 | 380 |
| 333 } // namespace content | 381 } // namespace content |
| OLD | NEW |