ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / renderer_host / p2p / socket_host_udp.cc
blobfd09f7d30534e890287c0e9ee94c614813199351
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/p2p/socket_host_udp.h"
7 #include "base/bind.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/metrics/histogram.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/trace_event/trace_event.h"
13 #include "content/browser/renderer_host/p2p/socket_host_throttler.h"
14 #include "content/common/p2p_messages.h"
15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/common/content_client.h"
17 #include "ipc/ipc_sender.h"
18 #include "net/base/io_buffer.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/net_util.h"
21 #include "third_party/webrtc/base/asyncpacketsocket.h"
23 namespace {
25 // UDP packets cannot be bigger than 64k.
26 const int kReadBufferSize = 65536;
27 // Socket receive buffer size.
28 const int kRecvSocketBufferSize = 65536; // 64K
30 // Defines set of transient errors. These errors are ignored when we get them
31 // from sendto() or recvfrom() calls.
33 // net::ERR_OUT_OF_MEMORY
35 // This is caused by ENOBUFS which means the buffer of the network interface
36 // is full.
38 // net::ERR_CONNECTION_RESET
40 // This is caused by WSAENETRESET or WSAECONNRESET which means the
41 // last send resulted in an "ICMP Port Unreachable" message.
42 bool IsTransientError(int error) {
43 return error == net::ERR_ADDRESS_UNREACHABLE ||
44 error == net::ERR_ADDRESS_INVALID ||
45 error == net::ERR_ACCESS_DENIED ||
46 error == net::ERR_CONNECTION_RESET ||
47 error == net::ERR_OUT_OF_MEMORY ||
48 error == net::ERR_INTERNET_DISCONNECTED;
51 } // namespace
53 namespace content {
55 P2PSocketHostUdp::PendingPacket::PendingPacket(
56 const net::IPEndPoint& to,
57 const std::vector<char>& content,
58 const rtc::PacketOptions& options,
59 uint64 id)
60 : to(to),
61 data(new net::IOBuffer(content.size())),
62 size(content.size()),
63 packet_options(options),
64 id(id) {
65 memcpy(data->data(), &content[0], size);
68 P2PSocketHostUdp::PendingPacket::~PendingPacket() {
71 P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender,
72 int socket_id,
73 P2PMessageThrottler* throttler)
74 : P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP),
75 socket_(
76 new net::UDPServerSocket(GetContentClient()->browser()->GetNetLog(),
77 net::NetLog::Source())),
78 send_pending_(false),
79 last_dscp_(net::DSCP_CS0),
80 throttler_(throttler),
81 send_buffer_size_(0) {
84 P2PSocketHostUdp::~P2PSocketHostUdp() {
85 if (state_ == STATE_OPEN) {
86 DCHECK(socket_.get());
87 socket_.reset();
91 void P2PSocketHostUdp::SetSendBufferSize() {
92 unsigned int send_buffer_size = 0;
94 base::StringToUint(
95 base::FieldTrialList::FindFullName("WebRTC-SystemUDPSendSocketSize"),
96 &send_buffer_size);
98 if (send_buffer_size > 0) {
99 if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size)) {
100 LOG(WARNING) << "Failed to set socket send buffer size to "
101 << send_buffer_size;
102 } else {
103 send_buffer_size_ = send_buffer_size;
108 bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address,
109 const P2PHostAndIPEndPoint& remote_address) {
110 DCHECK_EQ(state_, STATE_UNINITIALIZED);
112 int result = socket_->Listen(local_address);
113 if (result < 0) {
114 LOG(ERROR) << "bind() failed: " << result;
115 OnError();
116 return false;
119 // Setting recv socket buffer size.
120 if (socket_->SetReceiveBufferSize(kRecvSocketBufferSize) != net::OK) {
121 LOG(WARNING) << "Failed to set socket receive buffer size to "
122 << kRecvSocketBufferSize;
125 net::IPEndPoint address;
126 result = socket_->GetLocalAddress(&address);
127 if (result < 0) {
128 LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: "
129 << result;
130 OnError();
131 return false;
133 VLOG(1) << "Local address: " << address.ToString();
135 state_ = STATE_OPEN;
137 SetSendBufferSize();
139 // NOTE: Remote address will be same as what renderer provided.
140 message_sender_->Send(new P2PMsg_OnSocketCreated(
141 id_, address, remote_address.ip_address));
143 recv_buffer_ = new net::IOBuffer(kReadBufferSize);
144 DoRead();
146 return true;
149 void P2PSocketHostUdp::OnError() {
150 socket_.reset();
151 send_queue_.clear();
153 if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN)
154 message_sender_->Send(new P2PMsg_OnError(id_));
156 state_ = STATE_ERROR;
159 void P2PSocketHostUdp::DoRead() {
160 int result;
161 do {
162 result = socket_->RecvFrom(
163 recv_buffer_.get(),
164 kReadBufferSize,
165 &recv_address_,
166 base::Bind(&P2PSocketHostUdp::OnRecv, base::Unretained(this)));
167 if (result == net::ERR_IO_PENDING)
168 return;
169 HandleReadResult(result);
170 } while (state_ == STATE_OPEN);
173 void P2PSocketHostUdp::OnRecv(int result) {
174 HandleReadResult(result);
175 if (state_ == STATE_OPEN) {
176 DoRead();
180 void P2PSocketHostUdp::HandleReadResult(int result) {
181 DCHECK_EQ(STATE_OPEN, state_);
183 if (result > 0) {
184 std::vector<char> data(recv_buffer_->data(), recv_buffer_->data() + result);
186 if (!ContainsKey(connected_peers_, recv_address_)) {
187 P2PSocketHost::StunMessageType type;
188 bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
189 if ((stun && IsRequestOrResponse(type))) {
190 connected_peers_.insert(recv_address_);
191 } else if (!stun || type == STUN_DATA_INDICATION) {
192 LOG(ERROR) << "Received unexpected data packet from "
193 << recv_address_.ToString()
194 << " before STUN binding is finished.";
195 return;
199 message_sender_->Send(new P2PMsg_OnDataReceived(
200 id_, recv_address_, data, base::TimeTicks::Now()));
202 if (dump_incoming_rtp_packet_)
203 DumpRtpPacket(&data[0], data.size(), true);
204 } else if (result < 0 && !IsTransientError(result)) {
205 LOG(ERROR) << "Error when reading from UDP socket: " << result;
206 OnError();
210 void P2PSocketHostUdp::Send(const net::IPEndPoint& to,
211 const std::vector<char>& data,
212 const rtc::PacketOptions& options,
213 uint64 packet_id) {
214 if (!socket_) {
215 // The Send message may be sent after the an OnError message was
216 // sent by hasn't been processed the renderer.
217 return;
220 if (!ContainsKey(connected_peers_, to)) {
221 P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType();
222 bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
223 if (!stun || type == STUN_DATA_INDICATION) {
224 LOG(ERROR) << "Page tried to send a data packet to " << to.ToString()
225 << " before STUN binding is finished.";
226 OnError();
227 return;
230 if (throttler_->DropNextPacket(data.size())) {
231 VLOG(0) << "STUN message is dropped due to high volume.";
232 // Do not reset socket.
233 return;
237 IncrementTotalSentPackets();
239 if (send_pending_) {
240 send_queue_.push_back(PendingPacket(to, data, options, packet_id));
241 IncrementDelayedBytes(data.size());
242 IncrementDelayedPackets();
243 } else {
244 // TODO(mallinath: Remove unnecessary memcpy in this case.
245 PendingPacket packet(to, data, options, packet_id);
246 DoSend(packet);
250 void P2PSocketHostUdp::DoSend(const PendingPacket& packet) {
251 TRACE_EVENT_ASYNC_STEP_INTO1("p2p", "Send", packet.id, "UdpAsyncSendTo",
252 "size", packet.size);
253 // Don't try to set DSCP in following conditions,
254 // 1. If the outgoing packet is set to DSCP_NO_CHANGE
255 // 2. If no change in DSCP value from last packet
256 // 3. If there is any error in setting DSCP on socket.
257 net::DiffServCodePoint dscp =
258 static_cast<net::DiffServCodePoint>(packet.packet_options.dscp);
259 if (dscp != net::DSCP_NO_CHANGE && last_dscp_ != dscp &&
260 last_dscp_ != net::DSCP_NO_CHANGE) {
261 int result = socket_->SetDiffServCodePoint(dscp);
262 if (result == net::OK) {
263 last_dscp_ = dscp;
264 } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) {
265 // We receieved a non-transient error, and it seems we have
266 // not changed the DSCP in the past, disable DSCP as it unlikely
267 // to work in the future.
268 last_dscp_ = net::DSCP_NO_CHANGE;
272 uint64 tick_received = base::TimeTicks::Now().ToInternalValue();
274 packet_processing_helpers::ApplyPacketOptions(
275 packet.data->data(), packet.size, packet.packet_options, 0);
276 int result = socket_->SendTo(packet.data.get(),
277 packet.size,
278 packet.to,
279 base::Bind(&P2PSocketHostUdp::OnSend,
280 base::Unretained(this),
281 packet.id,
282 tick_received));
284 // sendto() may return an error, e.g. if we've received an ICMP Destination
285 // Unreachable message. When this happens try sending the same packet again,
286 // and just drop it if it fails again.
287 if (IsTransientError(result)) {
288 result = socket_->SendTo(packet.data.get(),
289 packet.size,
290 packet.to,
291 base::Bind(&P2PSocketHostUdp::OnSend,
292 base::Unretained(this),
293 packet.id,
294 tick_received));
297 if (result == net::ERR_IO_PENDING) {
298 send_pending_ = true;
299 } else {
300 HandleSendResult(packet.id, tick_received, result);
303 if (dump_outgoing_rtp_packet_)
304 DumpRtpPacket(packet.data->data(), packet.size, false);
307 void P2PSocketHostUdp::OnSend(uint64 packet_id,
308 uint64 tick_received,
309 int result) {
310 DCHECK(send_pending_);
311 DCHECK_NE(result, net::ERR_IO_PENDING);
313 send_pending_ = false;
315 HandleSendResult(packet_id, tick_received, result);
317 // Send next packets if we have them waiting in the buffer.
318 while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) {
319 PendingPacket packet = send_queue_.front();
320 DoSend(packet);
321 send_queue_.pop_front();
322 DecrementDelayedBytes(packet.size);
326 void P2PSocketHostUdp::HandleSendResult(uint64 packet_id,
327 uint64 tick_received,
328 int result) {
329 TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id,
330 "result", result);
331 if (result < 0) {
332 if (!IsTransientError(result)) {
333 LOG(ERROR) << "Error when sending data in UDP socket: " << result;
334 OnError();
335 return;
337 VLOG(0) << "sendto() has failed twice returning a "
338 " transient error. Dropping the packet.";
341 // UMA to track the histograms from 1ms to 1 sec for how long a packet spends
342 // in the browser process.
343 UMA_HISTOGRAM_TIMES(
344 "WebRTC.SystemSendPacketDuration_UDP" /* name */,
345 base::TimeTicks::Now() -
346 base::TimeTicks::FromInternalValue(tick_received) /* sample */);
348 message_sender_->Send(
349 new P2PMsg_OnSendComplete(id_, P2PSendPacketMetrics(packet_id)));
352 P2PSocketHost* P2PSocketHostUdp::AcceptIncomingTcpConnection(
353 const net::IPEndPoint& remote_address, int id) {
354 NOTREACHED();
355 OnError();
356 return NULL;
359 bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) {
360 DCHECK_EQ(STATE_OPEN, state_);
361 switch (option) {
362 case P2P_SOCKET_OPT_RCVBUF:
363 return socket_->SetReceiveBufferSize(value) == net::OK;
364 case P2P_SOCKET_OPT_SNDBUF:
365 // Ignore any following call to set the send buffer size if we're under
366 // experiment.
367 if (send_buffer_size_ > 0) {
368 return true;
370 return socket_->SetSendBufferSize(value) == net::OK;
371 case P2P_SOCKET_OPT_DSCP:
372 return (net::OK == socket_->SetDiffServCodePoint(
373 static_cast<net::DiffServCodePoint>(value))) ? true : false;
374 default:
375 NOTREACHED();
376 return false;
380 } // namespace content