Chromium Code Reviews| Index: net/udp/udp_socket_win.cc |
| diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc |
| index 2f5549f8ed2bd16190ddca69c7f4ce746a63b5d6..e6902f59e7a5beadd6375ba6f30804254dfc462e 100644 |
| --- a/net/udp/udp_socket_win.cc |
| +++ b/net/udp/udp_socket_win.cc |
| @@ -53,13 +53,17 @@ class UDPSocketWin::Core : public base::RefCounted<Core> { |
| // The UDPSocketWin is going away. |
| void Detach() { socket_ = NULL; } |
| - // The separate OVERLAPPED variables for asynchronous operation. |
| - OVERLAPPED read_overlapped_; |
| - OVERLAPPED write_overlapped_; |
| + // Separate events for non-blocking IO operations. |
| + WSAEVENT read_event_; |
| + WSAEVENT write_event_; |
| // The buffers used in Read() and Write(). |
| scoped_refptr<IOBuffer> read_iobuffer_; |
| scoped_refptr<IOBuffer> write_iobuffer_; |
| + int read_iobuffer_len_; |
|
rvargas (doing something else)
2015/01/21 22:10:09
We are not supposed to have public variables. We s
Alpha Left Google
2015/01/22 01:01:25
Done.
|
| + int write_iobuffer_len_; |
| + bool non_blocking_reads_initialized_; |
| + bool non_blocking_writes_initialized_; |
| // The address storage passed to WSARecvFrom(). |
| SockaddrStorage recv_addr_storage_; |
| @@ -112,12 +116,13 @@ class UDPSocketWin::Core : public base::RefCounted<Core> { |
| UDPSocketWin::Core::Core(UDPSocketWin* socket) |
| : socket_(socket), |
| reader_(this), |
| - writer_(this) { |
| - memset(&read_overlapped_, 0, sizeof(read_overlapped_)); |
| - memset(&write_overlapped_, 0, sizeof(write_overlapped_)); |
| - |
| - read_overlapped_.hEvent = WSACreateEvent(); |
| - write_overlapped_.hEvent = WSACreateEvent(); |
| + writer_(this), |
| + read_iobuffer_len_(0), |
| + write_iobuffer_len_(0), |
| + non_blocking_reads_initialized_(false), |
| + non_blocking_writes_initialized_(false) { |
| + read_event_ = WSACreateEvent(); |
| + write_event_ = WSACreateEvent(); |
| } |
| UDPSocketWin::Core::~Core() { |
| @@ -125,24 +130,22 @@ UDPSocketWin::Core::~Core() { |
| read_watcher_.StopWatching(); |
| write_watcher_.StopWatching(); |
| - WSACloseEvent(read_overlapped_.hEvent); |
| - memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_)); |
| - WSACloseEvent(write_overlapped_.hEvent); |
| - memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_)); |
| + WSACloseEvent(read_event_); |
| + WSACloseEvent(write_event_); |
| } |
| void UDPSocketWin::Core::WatchForRead() { |
| // We grab an extra reference because there is an IO operation in progress. |
| // Balanced in ReadDelegate::OnObjectSignaled(). |
| AddRef(); |
| - read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); |
| + read_watcher_.StartWatching(read_event_, &reader_); |
| } |
| void UDPSocketWin::Core::WatchForWrite() { |
| // We grab an extra reference because there is an IO operation in progress. |
| // Balanced in WriteDelegate::OnObjectSignaled(). |
| AddRef(); |
| - write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_); |
| + write_watcher_.StartWatching(write_event_, &writer_); |
| } |
| void UDPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) { |
| @@ -151,7 +154,7 @@ void UDPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) { |
| FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| "UDPSocketWin_Core_ReadDelegate_OnObjectSignaled")); |
| - DCHECK_EQ(object, core_->read_overlapped_.hEvent); |
| + DCHECK_EQ(object, core_->read_event_); |
| if (core_->socket_) |
| core_->socket_->DidCompleteRead(); |
| @@ -164,7 +167,7 @@ void UDPSocketWin::Core::WriteDelegate::OnObjectSignaled(HANDLE object) { |
| FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| "UDPSocketWin_Core_WriteDelegate_OnObjectSignaled")); |
| - DCHECK_EQ(object, core_->write_overlapped_.hEvent); |
| + DCHECK_EQ(object, core_->write_event_); |
| if (core_->socket_) |
| core_->socket_->DidCompleteWrite(); |
| @@ -567,20 +570,36 @@ void UDPSocketWin::DoWriteCallback(int rv) { |
| } |
| void UDPSocketWin::DidCompleteRead() { |
| - DWORD num_bytes, flags; |
| - BOOL ok = WSAGetOverlappedResult(socket_, &core_->read_overlapped_, |
| - &num_bytes, FALSE, &flags); |
| - WSAResetEvent(core_->read_overlapped_.hEvent); |
| - int result = ok ? num_bytes : MapSystemError(WSAGetLastError()); |
| - // Convert address. |
| - if (recv_from_address_ && result >= 0) { |
| + WSANETWORKEVENTS network_events; |
| + int os_error = 0; |
| + int rv = WSAEnumNetworkEvents(socket_, core_->read_event_, &network_events); |
| + if (rv == SOCKET_ERROR) { |
| + os_error = WSAGetLastError(); |
| + rv = MapSystemError(os_error); |
| + DoReadCallback(rv); |
| + return; |
| + } else if (network_events.lNetworkEvents) { |
|
Ryan Hamilton
2015/01/21 04:03:35
nit: since there was a return in the previous bloc
Alpha Left Google
2015/01/22 01:01:25
Done.
|
| + DCHECK(network_events.lNetworkEvents & FD_READ); |
| + // If network_events.iErrorCode[FD_READ_BIT] is nonzero, still call |
| + // InternalRecvFrom() because it reports a more accurate error code. |
| + rv = InternalRecvFrom(core_->read_iobuffer_.get(), |
| + core_->read_iobuffer_len_, recv_from_address_); |
| + if (rv == ERR_IO_PENDING) |
| + return; |
| + } else { |
| + core_->WatchForRead(); |
|
Ryan Hamilton
2015/01/21 04:03:35
Out of curiosity, what conditions lead to this bra
Alpha Left Google
2015/01/22 01:01:26
This comes from tcp_socket_win.cc.
The comment th
|
| + return; |
| + } |
| + // Convert address if there's data received. |
| + if (recv_from_address_ && rv >= 0) { |
| if (!ReceiveAddressToIPEndpoint(recv_from_address_)) |
| - result = ERR_ADDRESS_INVALID; |
| + rv = ERR_ADDRESS_INVALID; |
| } |
| - LogRead(result, core_->read_iobuffer_->data()); |
| + LogRead(rv, core_->read_iobuffer_->data()); |
| core_->read_iobuffer_ = NULL; |
| + core_->read_iobuffer_len_ = 0; |
| recv_from_address_ = NULL; |
| - DoReadCallback(result); |
| + DoReadCallback(rv); |
| } |
| void UDPSocketWin::LogRead(int result, const char* bytes) const { |
| @@ -606,16 +625,31 @@ void UDPSocketWin::LogRead(int result, const char* bytes) const { |
| } |
| void UDPSocketWin::DidCompleteWrite() { |
| - DWORD num_bytes, flags; |
| - BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, |
| - &num_bytes, FALSE, &flags); |
| - WSAResetEvent(core_->write_overlapped_.hEvent); |
| - int result = ok ? num_bytes : MapSystemError(WSAGetLastError()); |
| - LogWrite(result, core_->write_iobuffer_->data(), send_to_address_.get()); |
| - |
| - send_to_address_.reset(); |
| + WSANETWORKEVENTS network_events; |
| + int os_error = 0; |
| + int rv = WSAEnumNetworkEvents(socket_, core_->write_event_, &network_events); |
| + if (rv == SOCKET_ERROR) { |
| + os_error = WSAGetLastError(); |
| + rv = MapSystemError(os_error); |
| + DoWriteCallback(rv); |
| + return; |
| + } else if (network_events.lNetworkEvents) { |
| + DCHECK(network_events.lNetworkEvents & FD_WRITE); |
| + // If network_events.iErrorCode[FD_WRITE_BIT] is nonzero, still call |
| + // InternalSendto() because it reports a more accurate error code. |
| + rv = InternalSendTo(core_->write_iobuffer_.get(), |
| + core_->write_iobuffer_len_, send_to_address_.get()); |
| + if (rv == ERR_IO_PENDING) |
| + return; |
| + } else { |
| + core_->WatchForWrite(); |
| + return; |
| + } |
| + LogWrite(rv, core_->write_iobuffer_->data(), send_to_address_.get()); |
| core_->write_iobuffer_ = NULL; |
| - DoWriteCallback(result); |
| + core_->write_iobuffer_len_ = 0; |
| + send_to_address_.reset(); |
| + DoWriteCallback(rv); |
| } |
| void UDPSocketWin::LogWrite(int result, |
| @@ -639,7 +673,12 @@ void UDPSocketWin::LogWrite(int result, |
| int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len, |
| IPEndPoint* address) { |
| - DCHECK(!core_->read_iobuffer_.get()); |
| + if (!core_->non_blocking_reads_initialized_) { |
| + // After this call we'll receive FD_READ signals when asynchronous read |
|
rvargas (doing something else)
2015/01/21 22:10:09
nit: after this call the event will be signaled
Alpha Left Google
2015/01/22 01:01:25
Done.
|
| + // is completed. |
| + WSAEventSelect(socket_, core_->read_event_, FD_READ); |
| + core_->non_blocking_reads_initialized_ = true; |
| + } |
| SockaddrStorage& storage = core_->recv_addr_storage_; |
| storage.addr_len = sizeof(storage.addr_storage); |
| @@ -648,38 +687,40 @@ int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len, |
| read_buffer.len = buf_len; |
| DWORD flags = 0; |
| - DWORD num; |
| + DWORD bytes_read; |
| CHECK_NE(INVALID_SOCKET, socket_); |
| - AssertEventNotSignaled(core_->read_overlapped_.hEvent); |
| - int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, storage.addr, |
| - &storage.addr_len, &core_->read_overlapped_, NULL); |
| - if (rv == 0) { |
| - if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { |
| - int result = num; |
| - // Convert address. |
| - if (address && result >= 0) { |
| - if (!ReceiveAddressToIPEndpoint(address)) |
| - result = ERR_ADDRESS_INVALID; |
| - } |
| - LogRead(result, buf->data()); |
| - return result; |
| + int rv = WSARecvFrom(socket_, &read_buffer, 1, &bytes_read, &flags, |
|
rvargas (doing something else)
2015/01/21 22:10:09
Looks like there's no reason to use WSARecvFrom ov
Alpha Left Google
2015/01/22 01:01:25
Done.
|
| + storage.addr, &storage.addr_len, NULL, NULL); |
| + if (rv == SOCKET_ERROR) { |
| + int os_error = WSAGetLastError(); |
| + if (os_error != WSAEWOULDBLOCK) { |
| + rv = MapSystemError(os_error); |
| + LogRead(rv, NULL); |
| + return rv; |
| } |
| } else { |
| - int os_error = WSAGetLastError(); |
| - if (os_error != WSA_IO_PENDING) { |
| - int result = MapSystemError(os_error); |
| - LogRead(result, NULL); |
| - return result; |
| + rv = bytes_read; |
| + // Convert address. |
| + if (address && rv >= 0 && !ReceiveAddressToIPEndpoint(address)) { |
| + rv = ERR_ADDRESS_INVALID; |
| } |
| + LogRead(rv, buf->data()); |
| + return rv; |
| } |
| core_->WatchForRead(); |
| core_->read_iobuffer_ = buf; |
| + core_->read_iobuffer_len_ = buf_len; |
| return ERR_IO_PENDING; |
| } |
| int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len, |
| const IPEndPoint* address) { |
| - DCHECK(!core_->write_iobuffer_.get()); |
| + if (!core_->non_blocking_writes_initialized_) { |
| + // After this call we'll receive FD_WRITE signals when asynchronous write |
| + // is completed. |
| + WSAEventSelect(socket_, core_->write_event_, FD_WRITE); |
| + core_->non_blocking_writes_initialized_ = true; |
| + } |
| SockaddrStorage storage; |
| struct sockaddr* addr = storage.addr; |
| // Convert address. |
| @@ -699,27 +740,24 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len, |
| write_buffer.len = buf_len; |
| DWORD flags = 0; |
| - DWORD num; |
| - AssertEventNotSignaled(core_->write_overlapped_.hEvent); |
| - int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags, |
| - addr, storage.addr_len, &core_->write_overlapped_, NULL); |
| - if (rv == 0) { |
| - if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { |
| - int result = num; |
| - LogWrite(result, buf->data(), address); |
| - return result; |
| - } |
| - } else { |
| + DWORD bytes_written; |
| + int rv = WSASendTo(socket_, &write_buffer, 1, &bytes_written, flags, addr, |
| + storage.addr_len, NULL, NULL); |
| + if (rv == SOCKET_ERROR) { |
| int os_error = WSAGetLastError(); |
| - if (os_error != WSA_IO_PENDING) { |
| - int result = MapSystemError(os_error); |
| - LogWrite(result, NULL, NULL); |
| - return result; |
| + if (os_error != WSAEWOULDBLOCK) { |
| + rv = MapSystemError(os_error); |
| + LogWrite(rv, NULL, NULL); |
| + return rv; |
| } |
| + } else { |
| + rv = bytes_written; |
| + LogWrite(rv, buf->data(), address); |
| + return rv; |
| } |
| - |
| core_->WatchForWrite(); |
| core_->write_iobuffer_ = buf; |
| + core_->write_iobuffer_len_ = buf_len; |
| return ERR_IO_PENDING; |
| } |