diff options
author | Steve Anton <steveanton@webrtc.org> | 2020-01-31 10:31:53 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-03 21:19:57 +0000 |
commit | 3fa2b80e14fa8b9e05ca8efaf539e43a2cc46921 (patch) | |
tree | 82d4945eeea7bb774a48a324a05fd32591763ff6 /rtc_base | |
parent | 2181228624d1be60903c4e3352629290b9c3b27a (diff) | |
download | webrtc-3fa2b80e14fa8b9e05ca8efaf539e43a2cc46921.tar.gz |
AsyncTCPSocket: try sending outgoing data until EWOULDBLOCK
The AsyncTCPSocket is an AsyncPacketSocket which means it
emulates UDP-like (packet) semantics via a TCP stream. When
sending, if the entire packet could not be written then the
packet socket should indicate it wrote the whole thing and
flush out the remaining later when the socket is available.
The WriteEvent signal was already wired up but was not getting
fired (at least with the virtual sockets) since it would not
call Send() enough on the underlying socket to get an
EWOULDBLOCK that would register the async event.
This changes AsyncTCPSocket to repeatedly call Send() on the
underlying socket until the entire packet has been written
or EWOULDBLOCK was returned.
Bug: webrtc:6655
Change-Id: I41e81e0c106c9b3e712a8a0f792d28745d93f2d2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168083
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30449}
Diffstat (limited to 'rtc_base')
-rw-r--r-- | rtc_base/async_tcp_socket.cc | 56 | ||||
-rw-r--r-- | rtc_base/async_tcp_socket.h | 1 |
2 files changed, 33 insertions, 24 deletions
diff --git a/rtc_base/async_tcp_socket.cc b/rtc_base/async_tcp_socket.cc index d03ae32dde..35401d7c0a 100644 --- a/rtc_base/async_tcp_socket.cc +++ b/rtc_base/async_tcp_socket.cc @@ -16,6 +16,7 @@ #include <algorithm> #include <memory> +#include "api/array_view.h" #include "rtc_base/byte_order.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -147,33 +148,42 @@ int AsyncTCPSocketBase::SendTo(const void* pv, return -1; } -int AsyncTCPSocketBase::SendRaw(const void* pv, size_t cb) { - if (outbuf_.size() + cb > max_outsize_) { - socket_->SetError(EMSGSIZE); - return -1; - } - - RTC_DCHECK(!listen_); - outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb); - - return FlushOutBuffer(); -} - int AsyncTCPSocketBase::FlushOutBuffer() { RTC_DCHECK(!listen_); - int res = socket_->Send(outbuf_.data(), outbuf_.size()); - if (res <= 0) { - return res; - } - if (static_cast<size_t>(res) > outbuf_.size()) { - RTC_NOTREACHED(); - return -1; + RTC_DCHECK_GT(outbuf_.size(), 0); + rtc::ArrayView<uint8_t> view = outbuf_; + int res; + while (view.size() > 0) { + res = socket_->Send(view.data(), view.size()); + if (res <= 0) { + break; + } + if (static_cast<size_t>(res) > view.size()) { + RTC_NOTREACHED(); + res = -1; + break; + } + view = view.subview(res); } - size_t new_size = outbuf_.size() - res; - if (new_size > 0) { - memmove(outbuf_.data(), outbuf_.data() + res, new_size); + if (res > 0) { + // The output buffer may have been written out over multiple partial Send(), + // so reconstruct the total written length. + RTC_DCHECK_EQ(view.size(), 0); + res = outbuf_.size(); + outbuf_.Clear(); + } else { + // There was an error when calling Send(), so there will still be data left + // to send at a later point. + RTC_DCHECK_GT(view.size(), 0); + // In the special case of EWOULDBLOCK, signal that we had a partial write. + if (socket_->GetError() == EWOULDBLOCK) { + res = outbuf_.size() - view.size(); + } + if (view.size() < outbuf_.size()) { + memmove(outbuf_.data(), view.data(), view.size()); + outbuf_.SetSize(view.size()); + } } - outbuf_.SetSize(new_size); return res; } diff --git a/rtc_base/async_tcp_socket.h b/rtc_base/async_tcp_socket.h index fecaba798c..e05cce1ec9 100644 --- a/rtc_base/async_tcp_socket.h +++ b/rtc_base/async_tcp_socket.h @@ -61,7 +61,6 @@ class AsyncTCPSocketBase : public AsyncPacketSocket { static AsyncSocket* ConnectSocket(AsyncSocket* socket, const SocketAddress& bind_address, const SocketAddress& remote_address); - virtual int SendRaw(const void* pv, size_t cb); int FlushOutBuffer(); // Add data to |outbuf_|. void AppendToOutBuffer(const void* pv, size_t cb); |