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" |
| 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 |