| Index: remoting/jingle_glue/chromium_socket_factory.cc
|
| diff --git a/remoting/jingle_glue/chromium_socket_factory.cc b/remoting/jingle_glue/chromium_socket_factory.cc
|
| index c88833fa9bc167260254001c38a6d7ede0e63386..4983e04eb7464dd7cfb7f0ecfc88a11cb4dc0f15 100644
|
| --- a/remoting/jingle_glue/chromium_socket_factory.cc
|
| +++ b/remoting/jingle_glue/chromium_socket_factory.cc
|
| @@ -28,11 +28,46 @@ const int kReceiveBufferSize = 65536;
|
| // reached under normal conditions.
|
| const int kMaxSendBufferSize = 256 * 1024;
|
|
|
| -// Defines set of transient errors. These errors are ignored when we get them
|
| -// from sendto() calls.
|
| -bool IsTransientError(int error) {
|
| - return error == net::ERR_ADDRESS_UNREACHABLE ||
|
| - error == net::ERR_ADDRESS_INVALID;
|
| +// Enum for different actions that can be taken after sendto() returns an error.
|
| +enum ErrorAction {
|
| + ERROR_ACTION_FAIL,
|
| + ERROR_ACTION_IGNORE,
|
| + ERROR_ACTION_RETRY,
|
| +};
|
| +
|
| +// Returns true if |error| must be ignored when returned from sendto(). |retry|
|
| +// is set set when sentto() should be called for the same packet again.
|
| +//
|
| +// Keep this logic in sync with GetErrorAction() in
|
| +// remoting/client/plugin/pepper_packet_socket_factory.cc .
|
| +ErrorAction GetErrorAction(int error) {
|
| + switch (error) {
|
| + // UDP is connectionless, so we may receive ICMP unreachable or reset errors
|
| + // for previous sends to different addresses.
|
| + case net::ERR_ADDRESS_UNREACHABLE:
|
| + case net::ERR_CONNECTION_RESET:
|
| + return ERROR_ACTION_RETRY;
|
| +
|
| + // Target address is invalid. The socket is still usable for different
|
| + // target addresses and the error can be ignored.
|
| + case net::ERR_ADDRESS_INVALID:
|
| + return ERROR_ACTION_IGNORE;
|
| +
|
| + // May be returned when the packet is blocked by local firewall (see
|
| + // https://code.google.com/p/webrtc/issues/detail?id=1207). The firewall may
|
| + // still allow us to send to other addresses, so ignore the error for this
|
| + // particular send.
|
| + case net::ERR_ACCESS_DENIED:
|
| + return ERROR_ACTION_IGNORE;
|
| +
|
| + // Indicates that the buffer in the network adapter is full, so drop this
|
| + // packet and assume the socket is still usable.
|
| + case net::ERR_OUT_OF_MEMORY:
|
| + return ERROR_ACTION_IGNORE;
|
| +
|
| + default:
|
| + return ERROR_ACTION_FAIL;
|
| + }
|
| }
|
|
|
| class UdpPacketSocket : public talk_base::AsyncPacketSocket {
|
| @@ -66,6 +101,7 @@ class UdpPacketSocket : public talk_base::AsyncPacketSocket {
|
|
|
| scoped_refptr<net::IOBufferWithSize> data;
|
| net::IPEndPoint address;
|
| + bool retried;
|
| };
|
|
|
| void OnBindCompleted(int error);
|
| @@ -100,7 +136,8 @@ UdpPacketSocket::PendingPacket::PendingPacket(
|
| int buffer_size,
|
| const net::IPEndPoint& address)
|
| : data(new net::IOBufferWithSize(buffer_size)),
|
| - address(address) {
|
| + address(address),
|
| + retried(false) {
|
| memcpy(data->data(), buffer, buffer_size);
|
| }
|
|
|
| @@ -285,10 +322,24 @@ void UdpPacketSocket::OnSendCompleted(int result) {
|
| send_pending_ = false;
|
|
|
| if (result < 0) {
|
| - if (!IsTransientError(result)) {
|
| - LOG(ERROR) << "Send failed on a UDP socket: " << result;
|
| - error_ = EINVAL;
|
| - return;
|
| + ErrorAction action = GetErrorAction(result);
|
| + switch (action) {
|
| + case ERROR_ACTION_FAIL:
|
| + LOG(ERROR) << "Send failed on a UDP socket: " << result;
|
| + error_ = EINVAL;
|
| + return;
|
| +
|
| + case ERROR_ACTION_RETRY:
|
| + // Retry resending only once.
|
| + if (!send_queue_.front().retried) {
|
| + send_queue_.front().retried = true;
|
| + DoSend();
|
| + return;
|
| + }
|
| + break;
|
| +
|
| + case ERROR_ACTION_IGNORE:
|
| + break;
|
| }
|
| }
|
|
|
|
|