Fix win_write to check if fully sent (#28432)

* Fix win_write to check if fully sent

* Update tcp_windows.cc

* Update tcp_windows.cc
pull/31694/head
Sunyeop Lee 2 years ago committed by GitHub
parent 7e3ada34e6
commit 756fddec08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      src/core/lib/iomgr/tcp_windows.cc

@ -330,7 +330,7 @@ static void on_write(void* tcpp, grpc_error_handle error) {
if (info->wsa_error != 0) {
error = GRPC_WSA_ERROR(info->wsa_error, "WSASend");
} else {
GPR_ASSERT(info->bytes_transferred == tcp->write_slices->length);
GPR_ASSERT(info->bytes_transferred <= tcp->write_slices->length);
}
}
@ -350,7 +350,7 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
WSABUF local_buffers[MAX_WSABUF_COUNT];
WSABUF* allocated = NULL;
WSABUF* buffers = local_buffers;
size_t len;
size_t len, async_buffers_offset = 0;
if (grpc_tcp_trace.enabled()) {
size_t i;
@ -391,18 +391,39 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
/* First, let's try a synchronous, non-blocking write. */
status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
&bytes_sent, 0, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
/* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
connection that has its send queue filled up. But if we don't, then we can
avoid doing an async write operation at all. */
if (info->wsa_error != WSAEWOULDBLOCK) {
grpc_error_handle error = status == 0
? absl::OkStatus()
: GRPC_WSA_ERROR(info->wsa_error, "WSASend");
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
if (allocated) gpr_free(allocated);
return;
if (status == 0) {
if (bytes_sent == tcp->write_slices->length) {
info->wsa_error = 0;
grpc_error_handle error = absl::OkStatus();
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
if (allocated) gpr_free(allocated);
return;
}
/* The data was not completely delivered, we should send the rest of
them by doing an async write operation. */
for (i = 0; i < tcp->write_slices->count; i++) {
if (buffers[i].len > bytes_sent) {
buffers[i].buf += bytes_sent;
buffers[i].len -= bytes_sent;
break;
}
bytes_sent -= buffers[i].len;
async_buffers_offset++;
}
} else {
info->wsa_error = WSAGetLastError();
/* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a
busy connection that has its send queue filled up. But if we don't, then
we can avoid doing an async write operation at all. */
if (info->wsa_error != WSAEWOULDBLOCK) {
grpc_error_handle error = GRPC_WSA_ERROR(info->wsa_error, "WSASend");
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
if (allocated) gpr_free(allocated);
return;
}
}
TCP_REF(tcp, "write");
@ -410,8 +431,9 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
/* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
operation, this time asynchronously. */
memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
&bytes_sent, 0, &socket->write_info.overlapped, NULL);
status = WSASend(socket->socket, buffers + async_buffers_offset,
(DWORD)(tcp->write_slices->count - async_buffers_offset),
NULL, 0, &socket->write_info.overlapped, NULL);
if (allocated) gpr_free(allocated);
if (status != 0) {

Loading…
Cancel
Save