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 "remoting/client/plugin/pepper_packet_socket_factory.h" | 5 #include "remoting/client/plugin/pepper_packet_socket_factory.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "net/base/io_buffer.h" | 9 #include "net/base/io_buffer.h" |
10 #include "ppapi/cpp/net_address.h" | 10 #include "ppapi/cpp/net_address.h" |
11 #include "ppapi/cpp/udp_socket.h" | 11 #include "ppapi/cpp/udp_socket.h" |
12 #include "ppapi/utility/completion_callback_factory.h" | 12 #include "ppapi/utility/completion_callback_factory.h" |
13 #include "remoting/client/plugin/pepper_util.h" | 13 #include "remoting/client/plugin/pepper_util.h" |
14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | 14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" |
15 | 15 |
16 namespace remoting { | 16 namespace remoting { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 // Size of the buffer to allocate for RecvFrom(). | 20 // Size of the buffer to allocate for RecvFrom(). |
21 const int kReceiveBufferSize = 65536; | 21 const int kReceiveBufferSize = 65536; |
22 | 22 |
23 // Maximum amount of data in the send buffers. This is necessary to | 23 // Maximum amount of data in the send buffers. This is necessary to |
24 // prevent out-of-memory crashes if the caller sends data faster than | 24 // prevent out-of-memory crashes if the caller sends data faster than |
25 // Pepper's UDP API can handle it. This maximum should never be | 25 // Pepper's UDP API can handle it. This maximum should never be |
26 // reached under normal conditions. | 26 // reached under normal conditions. |
27 const int kMaxSendBufferSize = 256 * 1024; | 27 const int kMaxSendBufferSize = 256 * 1024; |
28 | 28 |
| 29 // Enum for different actions that can be taken after sendto() returns an error. |
| 30 enum ErrorAction { |
| 31 ERROR_ACTION_FAIL, |
| 32 ERROR_ACTION_IGNORE, |
| 33 ERROR_ACTION_RETRY, |
| 34 }; |
| 35 |
| 36 // Returns ErrorAction to perform if sendto() fails with |error|. |
| 37 ErrorAction GetErrorAction(int error) { |
| 38 switch (error) { |
| 39 // UDP is connectionless, so we may receive ICMP unreachable or reset errors |
| 40 // for previous sends to different addresses. |
| 41 case PP_ERROR_ADDRESS_UNREACHABLE: |
| 42 case PP_ERROR_CONNECTION_RESET: |
| 43 return ERROR_ACTION_RETRY; |
| 44 |
| 45 // Target address is invalid. The socket is still usable for different |
| 46 // target addresses and the error can be ignored. |
| 47 case PP_ERROR_ADDRESS_INVALID: |
| 48 return ERROR_ACTION_IGNORE; |
| 49 |
| 50 // May be returned when the packet is blocked by local firewall (see |
| 51 // https://code.google.com/p/webrtc/issues/detail?id=1207). The firewall may |
| 52 // still allow us to send to other addresses, so ignore the error for this |
| 53 // particular send. |
| 54 case PP_ERROR_NOACCESS: |
| 55 return ERROR_ACTION_IGNORE; |
| 56 |
| 57 // Indicates that the buffer in the network adapter is full, so drop this |
| 58 // packet and assume the socket is still usable. |
| 59 case PP_ERROR_NOMEMORY: |
| 60 return ERROR_ACTION_IGNORE; |
| 61 |
| 62 default: |
| 63 return ERROR_ACTION_FAIL; |
| 64 } |
| 65 } |
| 66 |
29 class UdpPacketSocket : public talk_base::AsyncPacketSocket { | 67 class UdpPacketSocket : public talk_base::AsyncPacketSocket { |
30 public: | 68 public: |
31 explicit UdpPacketSocket(const pp::InstanceHandle& instance); | 69 explicit UdpPacketSocket(const pp::InstanceHandle& instance); |
32 virtual ~UdpPacketSocket(); | 70 virtual ~UdpPacketSocket(); |
33 | 71 |
34 // |min_port| and |max_port| are set to zero if the port number | 72 // |min_port| and |max_port| are set to zero if the port number |
35 // should be assigned by the OS. | 73 // should be assigned by the OS. |
36 bool Init(const talk_base::SocketAddress& local_address, | 74 bool Init(const talk_base::SocketAddress& local_address, |
37 int min_port, | 75 int min_port, |
38 int max_port); | 76 int max_port); |
(...skipping 15 matching lines...) Expand all Loading... |
54 virtual void SetError(int error) OVERRIDE; | 92 virtual void SetError(int error) OVERRIDE; |
55 | 93 |
56 private: | 94 private: |
57 struct PendingPacket { | 95 struct PendingPacket { |
58 PendingPacket(const void* buffer, | 96 PendingPacket(const void* buffer, |
59 int buffer_size, | 97 int buffer_size, |
60 const pp::NetAddress& address); | 98 const pp::NetAddress& address); |
61 | 99 |
62 scoped_refptr<net::IOBufferWithSize> data; | 100 scoped_refptr<net::IOBufferWithSize> data; |
63 pp::NetAddress address; | 101 pp::NetAddress address; |
| 102 bool retried; |
64 }; | 103 }; |
65 | 104 |
66 void OnBindCompleted(int error); | 105 void OnBindCompleted(int error); |
67 | 106 |
68 void DoSend(); | 107 void DoSend(); |
69 void OnSendCompleted(int result); | 108 void OnSendCompleted(int result); |
70 | 109 |
71 void DoRead(); | 110 void DoRead(); |
72 void OnReadCompleted(int result, pp::NetAddress address); | 111 void OnReadCompleted(int result, pp::NetAddress address); |
73 void HandleReadResult(int result, pp::NetAddress address); | 112 void HandleReadResult(int result, pp::NetAddress address); |
(...skipping 21 matching lines...) Expand all Loading... |
95 pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_; | 134 pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_; |
96 | 135 |
97 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); | 136 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); |
98 }; | 137 }; |
99 | 138 |
100 UdpPacketSocket::PendingPacket::PendingPacket( | 139 UdpPacketSocket::PendingPacket::PendingPacket( |
101 const void* buffer, | 140 const void* buffer, |
102 int buffer_size, | 141 int buffer_size, |
103 const pp::NetAddress& address) | 142 const pp::NetAddress& address) |
104 : data(new net::IOBufferWithSize(buffer_size)), | 143 : data(new net::IOBufferWithSize(buffer_size)), |
105 address(address) { | 144 address(address), |
| 145 retried(true) { |
106 memcpy(data->data(), buffer, buffer_size); | 146 memcpy(data->data(), buffer, buffer_size); |
107 } | 147 } |
108 | 148 |
109 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) | 149 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) |
110 : instance_(instance), | 150 : instance_(instance), |
111 socket_(instance), | 151 socket_(instance), |
112 state_(STATE_CLOSED), | 152 state_(STATE_CLOSED), |
113 error_(0), | 153 error_(0), |
114 min_port_(0), | 154 min_port_(0), |
115 max_port_(0), | 155 max_port_(0), |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 ++min_port_; | 210 ++min_port_; |
171 pp::NetAddress pp_local_address; | 211 pp::NetAddress pp_local_address; |
172 if (SocketAddressToPpNetAddressWithPort( | 212 if (SocketAddressToPpNetAddressWithPort( |
173 instance_, local_address_, &pp_local_address, min_port_)) { | 213 instance_, local_address_, &pp_local_address, min_port_)) { |
174 pp::CompletionCallback callback = | 214 pp::CompletionCallback callback = |
175 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted); | 215 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted); |
176 int result = socket_.Bind(pp_local_address, callback); | 216 int result = socket_.Bind(pp_local_address, callback); |
177 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | 217 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
178 } | 218 } |
179 } else { | 219 } else { |
180 LOG(ERROR) << "Failed to bind UDP socket: " << result; | 220 LOG(ERROR) << "Failed to bind UDP socket to " << local_address_.ToString() |
| 221 << ", error: " << result; |
181 } | 222 } |
182 } | 223 } |
183 | 224 |
184 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { | 225 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { |
185 DCHECK_EQ(state_, STATE_BOUND); | 226 DCHECK_EQ(state_, STATE_BOUND); |
186 return local_address_; | 227 return local_address_; |
187 } | 228 } |
188 | 229 |
189 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { | 230 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { |
190 // UDP sockets are not connected - this method should never be called. | 231 // UDP sockets are not connected - this method should never be called. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 if (result == PP_ERROR_ABORTED) { | 315 if (result == PP_ERROR_ABORTED) { |
275 // Send is aborted when the socket is being destroyed. | 316 // Send is aborted when the socket is being destroyed. |
276 // |send_queue_| may be already destroyed, it's not safe to access | 317 // |send_queue_| may be already destroyed, it's not safe to access |
277 // it here. | 318 // it here. |
278 return; | 319 return; |
279 } | 320 } |
280 | 321 |
281 send_pending_ = false; | 322 send_pending_ = false; |
282 | 323 |
283 if (result < 0) { | 324 if (result < 0) { |
284 LOG(ERROR) << "Send failed on a UDP socket: " << result; | 325 ErrorAction action = GetErrorAction(result); |
| 326 switch (action) { |
| 327 case ERROR_ACTION_FAIL: |
| 328 LOG(ERROR) << "Send failed on a UDP socket: " << result; |
| 329 error_ = EINVAL; |
| 330 return; |
285 | 331 |
286 // OS (e.g. OSX) may return EHOSTUNREACH when the peer has the | 332 case ERROR_ACTION_RETRY: |
287 // same subnet address as the local host but connected to a | 333 // Retry resending only once. |
288 // different network. That error must be ingored because the | 334 if (!send_queue_.front().retried) { |
289 // socket may still be useful for other ICE canidadates (e.g. for | 335 send_queue_.front().retried = true; |
290 // STUN candidates with a different address). Unfortunately pepper | 336 DoSend(); |
291 // interface currently returns PP_ERROR_FAILED for any error (see | 337 return; |
292 // crbug.com/136406). It's not possible to distinguish that case | 338 } |
293 // from other errors and so we have to ingore all of them. This | 339 break; |
294 // behavior matchers the libjingle's AsyncUDPSocket used by the | |
295 // host. | |
296 // | |
297 // TODO(sergeyu): Once implementation of the Pepper UDP interface | |
298 // is fixed, uncomment the code below, but ignore | |
299 // host-unreacheable error. | |
300 | 340 |
301 // error_ = EINVAL; | 341 case ERROR_ACTION_IGNORE: |
302 // return; | 342 break; |
| 343 } |
303 } | 344 } |
304 | 345 |
305 send_queue_size_ -= send_queue_.front().data->size(); | 346 send_queue_size_ -= send_queue_.front().data->size(); |
306 send_queue_.pop_front(); | 347 send_queue_.pop_front(); |
307 DoSend(); | 348 DoSend(); |
308 } | 349 } |
309 | 350 |
310 void UdpPacketSocket::DoRead() { | 351 void UdpPacketSocket::DoRead() { |
311 receive_buffer_.resize(kReceiveBufferSize); | 352 receive_buffer_.resize(kReceiveBufferSize); |
312 pp::CompletionCallbackWithOutput<pp::NetAddress> callback = | 353 pp::CompletionCallbackWithOutput<pp::NetAddress> callback = |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 return NULL; | 417 return NULL; |
377 } | 418 } |
378 | 419 |
379 talk_base::AsyncResolverInterface* | 420 talk_base::AsyncResolverInterface* |
380 PepperPacketSocketFactory::CreateAsyncResolver() { | 421 PepperPacketSocketFactory::CreateAsyncResolver() { |
381 NOTREACHED(); | 422 NOTREACHED(); |
382 return NULL; | 423 return NULL; |
383 } | 424 } |
384 | 425 |
385 } // namespace remoting | 426 } // namespace remoting |
OLD | NEW |