| Index: net/base/tcp_listen_socket.cc
|
| ===================================================================
|
| --- net/base/tcp_listen_socket.cc (revision 135347)
|
| +++ net/base/tcp_listen_socket.cc (working copy)
|
| @@ -17,6 +17,7 @@
|
| #include "net/base/net_errors.h"
|
| #endif
|
|
|
| +#include "base/bind.h"
|
| #include "base/eintr_wrapper.h"
|
| #include "base/sys_byteorder.h"
|
| #include "base/threading/platform_thread.h"
|
| @@ -25,6 +26,7 @@
|
|
|
| #if defined(OS_WIN)
|
| typedef int socklen_t;
|
| +#include "net/base/winsock_init.h"
|
| #endif // defined(OS_WIN)
|
|
|
| namespace net {
|
| @@ -32,7 +34,34 @@
|
| namespace {
|
|
|
| const int kReadBufSize = 4096;
|
| +const int kMaxSendBufSize = 1024 * 1024 * 5; // 5MB
|
|
|
| +const net::BackoffEntry::Policy kSendBackoffPolicy = {
|
| + // Number of initial errors (in sequence) to ignore before applying
|
| + // exponential back-off rules.
|
| + 0,
|
| +
|
| + // Initial delay for exponential back-off in ms.
|
| + 25,
|
| +
|
| + // Factor by which the waiting time will be multiplied.
|
| + 2,
|
| +
|
| + // Fuzzing percentage. ex: 10% will spread requests randomly
|
| + // between 90%-100% of the calculated time.
|
| + 0,
|
| +
|
| + // Maximum amount of time we are willing to delay our request in ms.
|
| + 100,
|
| +
|
| + // Time to keep an entry from being discarded even when it
|
| + // has no significant state, -1 to never discard.
|
| + -1,
|
| +
|
| + // Don't use initial delay unless the last request was an error.
|
| + false,
|
| +};
|
| +
|
| } // namespace
|
|
|
| #if defined(OS_WIN)
|
| @@ -75,7 +104,10 @@
|
| : ListenSocket(del),
|
| socket_(s),
|
| reads_paused_(false),
|
| - has_pending_reads_(false) {
|
| + has_pending_reads_(false),
|
| + send_pending_size_(0),
|
| + send_error_(false),
|
| + send_backoff_(&kSendBackoffPolicy) {
|
| #if defined(OS_WIN)
|
| socket_event_ = WSACreateEvent();
|
| // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT
|
| @@ -96,6 +128,10 @@
|
| }
|
|
|
| SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) {
|
| +#if defined(OS_WIN)
|
| + EnsureWinsockInit();
|
| +#endif
|
| +
|
| SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
| if (s != kInvalidSocket) {
|
| #if defined(OS_POSIX)
|
| @@ -132,33 +168,27 @@
|
| }
|
|
|
| void TCPListenSocket::SendInternal(const char* bytes, int len) {
|
| - char* send_buf = const_cast<char *>(bytes);
|
| - int len_left = len;
|
| - while (true) {
|
| - int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0));
|
| - if (sent == len_left) { // A shortcut to avoid extraneous checks.
|
| - break;
|
| - }
|
| - if (sent == kSocketError) {
|
| -#if defined(OS_WIN)
|
| - if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
| - LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
|
| -#elif defined(OS_POSIX)
|
| - if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
| - LOG(ERROR) << "send failed: errno==" << errno;
|
| -#endif
|
| - break;
|
| - }
|
| - // Otherwise we would block, and now we have to wait for a retry.
|
| - // Fall through to PlatformThread::YieldCurrentThread()
|
| - } else {
|
| - // sent != len_left according to the shortcut above.
|
| - // Shift the buffer start and send the remainder after a short while.
|
| - send_buf += sent;
|
| - len_left -= sent;
|
| - }
|
| - base::PlatformThread::YieldCurrentThread();
|
| + DCHECK(bytes);
|
| + DCHECK_GT(len, 0);
|
| +
|
| + if (send_error_)
|
| + return;
|
| +
|
| + if (send_pending_size_ + len > kMaxSendBufSize) {
|
| + LOG(ERROR) << "send failed: buffer overrun";
|
| + send_buffers_.clear();
|
| + send_pending_size_ = 0;
|
| + send_error_ = true;
|
| + return;
|
| }
|
| +
|
| + scoped_refptr<IOBuffer> buffer(new IOBuffer(len));
|
| + memcpy(buffer->data(), bytes, len);
|
| + send_buffers_.push_back(new DrainableIOBuffer(buffer, len));
|
| + send_pending_size_ += len;
|
| +
|
| + if (!send_timer_.IsRunning())
|
| + SendData();
|
| }
|
|
|
| void TCPListenSocket::Listen() {
|
| @@ -319,4 +349,63 @@
|
|
|
| #endif
|
|
|
| +void TCPListenSocket::SendData() {
|
| + DCHECK(!send_buffers_.empty());
|
| +
|
| + int total_sent = 0;
|
| +
|
| + // Send data until all buffers have been sent or a call would block.
|
| + while (!send_buffers_.empty()) {
|
| + scoped_refptr<DrainableIOBuffer> buffer = send_buffers_.front();
|
| +
|
| + int len_left = buffer->BytesRemaining();
|
| + int sent = HANDLE_EINTR(send(socket_, buffer->data(), len_left, 0));
|
| + if (sent > 0) {
|
| + if (sent == len_left)
|
| + send_buffers_.pop_front();
|
| + else
|
| + buffer->DidConsume(sent);
|
| +
|
| + total_sent += sent;
|
| + } else if (sent == kSocketError) {
|
| +#if defined(OS_WIN)
|
| + if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
| + LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
|
| +#elif defined(OS_POSIX)
|
| + if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
| + LOG(ERROR) << "send failed: errno==" << errno;
|
| +#endif
|
| + // Don't try to re-send data after a socket error.
|
| + send_buffers_.clear();
|
| + send_pending_size_ = 0;
|
| + send_error_ = true;
|
| + return;
|
| + }
|
| +
|
| + // The call would block. Don't send any more data at this time.
|
| + break;
|
| + } else {
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (total_sent > 0) {
|
| + send_pending_size_ -= total_sent;
|
| + DCHECK_GE(send_pending_size_, 0);
|
| +
|
| + // Clear the back-off delay.
|
| + send_backoff_.Reset();
|
| + } else {
|
| + // Increase the back-off delay.
|
| + send_backoff_.InformOfRequest(false);
|
| + }
|
| +
|
| + if (!send_buffers_.empty()) {
|
| + DCHECK(!send_timer_.IsRunning());
|
| + send_timer_.Start(FROM_HERE, send_backoff_.GetTimeUntilRelease(),
|
| + this, &TCPListenSocket::SendData);
|
| + }
|
| +}
|
| +
|
| } // namespace net
|
|
|