Index: net/base/tcp_listen_socket.cc |
diff --git a/net/base/tcp_listen_socket.cc b/net/base/tcp_listen_socket.cc |
index 4b4dbd3553ec50af9fcc8fba45290afd2cfb908a..c34a9191bf29614c6378d94f26b07122fd54850b 100644 |
--- a/net/base/tcp_listen_socket.cc |
+++ b/net/base/tcp_listen_socket.cc |
@@ -2,7 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "build/build_config.h" |
+#include "net/base/tcp_listen_socket.h" |
#if defined(OS_WIN) |
// winsock2.h must be included first in order to ensure it is included before |
@@ -17,117 +17,35 @@ |
#include "net/base/net_errors.h" |
#endif |
-#include "base/bind.h" |
-#include "base/eintr_wrapper.h" |
+#include "base/logging.h" |
#include "base/sys_byteorder.h" |
#include "base/threading/platform_thread.h" |
+#include "build/build_config.h" |
#include "net/base/net_util.h" |
-#include "net/base/tcp_listen_socket.h" |
- |
-#if defined(OS_WIN) |
-typedef int socklen_t; |
#include "net/base/winsock_init.h" |
-#endif // defined(OS_WIN) |
- |
-namespace net { |
- |
-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, |
+using std::string; |
- // Don't use initial delay unless the last request was an error. |
- false, |
-}; |
- |
-} // namespace |
- |
-#if defined(OS_WIN) |
-const SOCKET TCPListenSocket::kInvalidSocket = INVALID_SOCKET; |
-const int TCPListenSocket::kSocketError = SOCKET_ERROR; |
-#elif defined(OS_POSIX) |
-const SOCKET TCPListenSocket::kInvalidSocket = -1; |
-const int TCPListenSocket::kSocketError = -1; |
-#endif |
+namespace net { |
-TCPListenSocket* TCPListenSocket::CreateAndListen( |
- const std::string& ip, int port, ListenSocket::ListenSocketDelegate *del) { |
+// static |
+scoped_refptr<TCPListenSocket> TCPListenSocket::CreateAndListen( |
+ const string& ip, int port, StreamListenSocket::Delegate* del) { |
SOCKET s = CreateAndBind(ip, port); |
- if (s == kInvalidSocket) { |
- // TODO(erikkay): error handling |
- } else { |
- TCPListenSocket* sock = new TCPListenSocket(s, del); |
- sock->Listen(); |
- return sock; |
- } |
- return NULL; |
+ if (s == kInvalidSocket) |
+ return NULL; |
+ scoped_refptr<TCPListenSocket> sock(new TCPListenSocket(s, del)); |
+ sock->Listen(); |
+ return sock; |
} |
-void TCPListenSocket::PauseReads() { |
- DCHECK(!reads_paused_); |
- reads_paused_ = true; |
-} |
- |
-void TCPListenSocket::ResumeReads() { |
- DCHECK(reads_paused_); |
- reads_paused_ = false; |
- if (has_pending_reads_) { |
- has_pending_reads_ = false; |
- Read(); |
- } |
-} |
- |
-TCPListenSocket::TCPListenSocket(SOCKET s, |
- ListenSocket::ListenSocketDelegate *del) |
- : ListenSocket(del), |
- socket_(s), |
- reads_paused_(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 |
- WatchSocket(NOT_WAITING); |
-#elif defined(OS_POSIX) |
- wait_state_ = NOT_WAITING; |
-#endif |
+TCPListenSocket::TCPListenSocket(SOCKET s, StreamListenSocket::Delegate* del) |
+ : StreamListenSocket(s, del) { |
} |
-TCPListenSocket::~TCPListenSocket() { |
-#if defined(OS_WIN) |
- if (socket_event_) { |
- WSACloseEvent(socket_event_); |
- socket_event_ = WSA_INVALID_EVENT; |
- } |
-#endif |
- CloseSocket(socket_); |
-} |
+TCPListenSocket::~TCPListenSocket() {} |
-SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) { |
+SOCKET TCPListenSocket::CreateAndBind(const string& ip, int port) { |
#if defined(OS_WIN) |
EnsureWinsockInit(); |
#endif |
@@ -150,263 +68,24 @@ SOCKET TCPListenSocket::CreateAndBind(const std::string& ip, int port) { |
#elif defined(OS_POSIX) |
close(s); |
#endif |
+ LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; |
s = kInvalidSocket; |
} |
} |
return s; |
} |
-SOCKET TCPListenSocket::Accept(SOCKET s) { |
- sockaddr_in from; |
- socklen_t from_len = sizeof(from); |
- SOCKET conn = |
- HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len)); |
- if (conn != kInvalidSocket) { |
- SetNonBlocking(conn); |
- } |
- return conn; |
-} |
- |
-void TCPListenSocket::SendInternal(const char* bytes, int len) { |
- DCHECK(bytes); |
- if (!bytes || len <= 0) |
- return; |
- |
- 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() { |
- int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? |
- listen(socket_, backlog); |
- // TODO(erikkay): error handling |
-#if defined(OS_POSIX) |
- WatchSocket(WAITING_ACCEPT); |
-#endif |
-} |
- |
void TCPListenSocket::Accept() { |
- SOCKET conn = Accept(socket_); |
- if (conn != kInvalidSocket) { |
- scoped_refptr<TCPListenSocket> sock( |
- new TCPListenSocket(conn, socket_delegate_)); |
- // it's up to the delegate to AddRef if it wants to keep it around |
-#if defined(OS_POSIX) |
- sock->WatchSocket(WAITING_READ); |
-#endif |
- socket_delegate_->DidAccept(this, sock); |
- } else { |
- // TODO(ibrar): some error handling required here |
- } |
-} |
- |
-void TCPListenSocket::Read() { |
- char buf[kReadBufSize + 1]; // +1 for null termination |
- int len; |
- do { |
- len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0)); |
- if (len == kSocketError) { |
-#if defined(OS_WIN) |
- int err = WSAGetLastError(); |
- if (err == WSAEWOULDBLOCK) { |
-#elif defined(OS_POSIX) |
- if (errno == EWOULDBLOCK || errno == EAGAIN) { |
-#endif |
- break; |
- } else { |
- // TODO(ibrar): some error handling required here |
- break; |
- } |
- } else if (len == 0) { |
- // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need |
- // to call it here. |
-#if defined(OS_POSIX) |
- Close(); |
-#endif |
- } else { |
- // TODO(ibrar): maybe change DidRead to take a length instead |
- DCHECK_GT(len, 0); |
- DCHECK_LE(len, kReadBufSize); |
- buf[len] = 0; // already create a buffer with +1 length |
- socket_delegate_->DidRead(this, buf, len); |
- } |
- } while (len == kReadBufSize); |
-} |
- |
-void TCPListenSocket::Close() { |
-#if defined(OS_POSIX) |
- if (wait_state_ == NOT_WAITING) |
- return; |
- wait_state_ = NOT_WAITING; |
-#endif |
- UnwatchSocket(); |
- socket_delegate_->DidClose(this); |
-} |
- |
-void TCPListenSocket::CloseSocket(SOCKET s) { |
- if (s && s != kInvalidSocket) { |
- UnwatchSocket(); |
-#if defined(OS_WIN) |
- closesocket(s); |
-#elif defined(OS_POSIX) |
- close(s); |
-#endif |
- } |
-} |
- |
-void TCPListenSocket::WatchSocket(WaitState state) { |
-#if defined(OS_WIN) |
- WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ); |
- watcher_.StartWatching(socket_event_, this); |
-#elif defined(OS_POSIX) |
- // Implicitly calls StartWatchingFileDescriptor(). |
- MessageLoopForIO::current()->WatchFileDescriptor( |
- socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this); |
- wait_state_ = state; |
-#endif |
-} |
- |
-void TCPListenSocket::UnwatchSocket() { |
-#if defined(OS_WIN) |
- watcher_.StopWatching(); |
-#elif defined(OS_POSIX) |
- watcher_.StopWatchingFileDescriptor(); |
-#endif |
-} |
- |
-// TODO(ibrar): We can add these functions into OS dependent files |
-#if defined(OS_WIN) |
-// MessageLoop watcher callback |
-void TCPListenSocket::OnObjectSignaled(HANDLE object) { |
- WSANETWORKEVENTS ev; |
- if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) { |
- // TODO |
- return; |
- } |
- |
- // The object was reset by WSAEnumNetworkEvents. Watch for the next signal. |
- watcher_.StartWatching(object, this); |
- |
- if (ev.lNetworkEvents == 0) { |
- // Occasionally the event is set even though there is no new data. |
- // The net seems to think that this is ignorable. |
+ SOCKET conn = AcceptSocket(); |
+ if (conn == kInvalidSocket) |
return; |
- } |
- if (ev.lNetworkEvents & FD_ACCEPT) { |
- Accept(); |
- } |
- if (ev.lNetworkEvents & FD_READ) { |
- if (reads_paused_) { |
- has_pending_reads_ = true; |
- } else { |
- Read(); |
- } |
- } |
- if (ev.lNetworkEvents & FD_CLOSE) { |
- Close(); |
- } |
-} |
-#elif defined(OS_POSIX) |
-void TCPListenSocket::OnFileCanReadWithoutBlocking(int fd) { |
- switch (wait_state_) { |
- case WAITING_ACCEPT: |
- Accept(); |
- break; |
- case WAITING_READ: |
- if (reads_paused_) { |
- has_pending_reads_ = true; |
- } else { |
- Read(); |
- } |
- break; |
- default: |
- // Close() is called by Read() in the Linux case. |
- NOTREACHED(); |
- break; |
- } |
-} |
- |
-void TCPListenSocket::OnFileCanWriteWithoutBlocking(int fd) { |
- // MessagePumpLibevent callback, we don't listen for write events |
- // so we shouldn't ever reach here. |
- NOTREACHED(); |
-} |
- |
-#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; |
+ scoped_refptr<TCPListenSocket> sock( |
+ new TCPListenSocket(conn, socket_delegate_)); |
+ // It's up to the delegate to AddRef if it wants to keep it around. |
+#if defined(OS_POSIX) |
+ sock->WatchSocket(WAITING_READ); |
#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); |
- } |
+ socket_delegate_->DidAccept(this, sock); |
} |
} // namespace net |