| Index: net/socket/tcp_socket_win.cc
|
| diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
|
| index 2ec130ee1cbd68b2d50a38223091997d4015a914..f0aa149cfa36f43f0c963c6eb2a2aa068600df8d 100644
|
| --- a/net/socket/tcp_socket_win.cc
|
| +++ b/net/socket/tcp_socket_win.cc
|
| @@ -489,20 +489,52 @@ int TCPSocketWin::Read(IOBuffer* buf,
|
| int buf_len,
|
| const CompletionCallback& callback) {
|
| DCHECK(CalledOnValidThread());
|
| - DCHECK_NE(socket_, INVALID_SOCKET);
|
| - DCHECK(!waiting_read_);
|
| - CHECK(read_callback_.is_null());
|
| DCHECK(!core_->read_iobuffer_.get());
|
| -
|
| - return DoRead(buf, buf_len, callback);
|
| + // base::Unretained() is safe because RetryRead() won't be called when |this|
|
| + // is gone.
|
| + int rv =
|
| + ReadIfReady(buf, buf_len,
|
| + base::Bind(&TCPSocketWin::RetryRead, base::Unretained(this)));
|
| + if (rv != ERR_IO_PENDING)
|
| + return rv;
|
| + read_callback_ = callback;
|
| + core_->read_iobuffer_ = buf;
|
| + core_->read_buffer_length_ = buf_len;
|
| + return ERR_IO_PENDING;
|
| }
|
|
|
| int TCPSocketWin::ReadIfReady(IOBuffer* buf,
|
| int buf_len,
|
| const CompletionCallback& callback) {
|
| DCHECK(CalledOnValidThread());
|
| - // TODO(xunjieli): Implement this.
|
| - return ERR_READ_IF_READY_NOT_IMPLEMENTED;
|
| + DCHECK_NE(socket_, INVALID_SOCKET);
|
| + DCHECK(!waiting_read_);
|
| + DCHECK(read_if_ready_callback_.is_null());
|
| +
|
| + if (!core_->non_blocking_reads_initialized_) {
|
| + WSAEventSelect(socket_, core_->read_overlapped_.hEvent, FD_READ | FD_CLOSE);
|
| + core_->non_blocking_reads_initialized_ = true;
|
| + }
|
| + int rv = recv(socket_, buf->data(), buf_len, 0);
|
| + int os_error = WSAGetLastError();
|
| + if (rv == SOCKET_ERROR) {
|
| + if (os_error != WSAEWOULDBLOCK) {
|
| + int net_error = MapSystemError(os_error);
|
| + net_log_.AddEvent(NetLogEventType::SOCKET_READ_ERROR,
|
| + CreateNetLogSocketErrorCallback(net_error, os_error));
|
| + return net_error;
|
| + }
|
| + } else {
|
| + net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
|
| + buf->data());
|
| + NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
|
| + return rv;
|
| + }
|
| +
|
| + waiting_read_ = true;
|
| + read_if_ready_callback_ = callback;
|
| + core_->WatchForRead();
|
| + return ERR_IO_PENDING;
|
| }
|
|
|
| int TCPSocketWin::Write(IOBuffer* buf,
|
| @@ -685,6 +717,7 @@ void TCPSocketWin::Close() {
|
| waiting_write_ = false;
|
|
|
| read_callback_.Reset();
|
| + read_if_ready_callback_.Reset();
|
| write_callback_.Reset();
|
| peer_address_.reset();
|
| connect_os_error_ = 0;
|
| @@ -879,35 +912,21 @@ void TCPSocketWin::LogConnectEnd(int net_error) {
|
| sizeof(source_address)));
|
| }
|
|
|
| -int TCPSocketWin::DoRead(IOBuffer* buf, int buf_len,
|
| - const CompletionCallback& callback) {
|
| - if (!core_->non_blocking_reads_initialized_) {
|
| - WSAEventSelect(socket_, core_->read_overlapped_.hEvent,
|
| - FD_READ | FD_CLOSE);
|
| - core_->non_blocking_reads_initialized_ = true;
|
| - }
|
| - int rv = recv(socket_, buf->data(), buf_len, 0);
|
| - int os_error = WSAGetLastError();
|
| - if (rv == SOCKET_ERROR) {
|
| - if (os_error != WSAEWOULDBLOCK) {
|
| - int net_error = MapSystemError(os_error);
|
| - net_log_.AddEvent(NetLogEventType::SOCKET_READ_ERROR,
|
| - CreateNetLogSocketErrorCallback(net_error, os_error));
|
| - return net_error;
|
| - }
|
| - } else {
|
| - net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
|
| - buf->data());
|
| - NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
|
| - return rv;
|
| - }
|
| +void TCPSocketWin::RetryRead(int rv) {
|
| + DCHECK(core_->read_iobuffer_);
|
|
|
| - waiting_read_ = true;
|
| - read_callback_ = callback;
|
| - core_->read_iobuffer_ = buf;
|
| - core_->read_buffer_length_ = buf_len;
|
| - core_->WatchForRead();
|
| - return ERR_IO_PENDING;
|
| + if (rv == OK) {
|
| + // base::Unretained() is safe because RetryRead() won't be called when
|
| + // |this| is gone.
|
| + rv = ReadIfReady(
|
| + core_->read_iobuffer_.get(), core_->read_buffer_length_,
|
| + base::Bind(&TCPSocketWin::RetryRead, base::Unretained(this)));
|
| + if (rv == ERR_IO_PENDING)
|
| + return;
|
| + }
|
| + core_->read_iobuffer_ = nullptr;
|
| + core_->read_buffer_length_ = 0;
|
| + base::ResetAndReturn(&read_callback_).Run(rv);
|
| }
|
|
|
| void TCPSocketWin::DidCompleteConnect() {
|
| @@ -989,7 +1008,7 @@ void TCPSocketWin::DidCompleteWrite() {
|
|
|
| void TCPSocketWin::DidSignalRead() {
|
| DCHECK(waiting_read_);
|
| - DCHECK(!read_callback_.is_null());
|
| + DCHECK(!read_if_ready_callback_.is_null());
|
|
|
| int os_error = 0;
|
| WSANETWORKEVENTS network_events;
|
| @@ -1010,20 +1029,17 @@ void TCPSocketWin::DidSignalRead() {
|
| // network_events.iErrorCode[FD_CLOSE_BIT] is 0, it is a graceful
|
| // connection closure. It is tempting to directly set rv to 0 in
|
| // this case, but the MSDN pages for WSAEventSelect and
|
| - // WSAAsyncSelect recommend we still call DoRead():
|
| + // WSAAsyncSelect recommend we still call RetryRead():
|
| // FD_CLOSE should only be posted after all data is read from a
|
| // socket, but an application should check for remaining data upon
|
| // receipt of FD_CLOSE to avoid any possibility of losing data.
|
| //
|
| // If network_events.iErrorCode[FD_READ_BIT] or
|
| // network_events.iErrorCode[FD_CLOSE_BIT] is nonzero, still call
|
| - // DoRead() because recv() reports a more accurate error code
|
| + // RetryRead() because recv() reports a more accurate error code
|
| // (WSAECONNRESET vs. WSAECONNABORTED) when the connection was
|
| // reset.
|
| - rv = DoRead(core_->read_iobuffer_.get(), core_->read_buffer_length_,
|
| - read_callback_);
|
| - if (rv == ERR_IO_PENDING)
|
| - return;
|
| + rv = OK;
|
| } else {
|
| // This may happen because Read() may succeed synchronously and
|
| // consume all the received data without resetting the event object.
|
| @@ -1031,12 +1047,9 @@ void TCPSocketWin::DidSignalRead() {
|
| return;
|
| }
|
|
|
| - waiting_read_ = false;
|
| - core_->read_iobuffer_ = NULL;
|
| - core_->read_buffer_length_ = 0;
|
| -
|
| DCHECK_NE(rv, ERR_IO_PENDING);
|
| - base::ResetAndReturn(&read_callback_).Run(rv);
|
| + waiting_read_ = false;
|
| + base::ResetAndReturn(&read_if_ready_callback_).Run(rv);
|
| }
|
|
|
| bool TCPSocketWin::GetEstimatedRoundTripTime(base::TimeDelta* out_rtt) const {
|
|
|