Skip to content

Commit

Permalink
Fix win_write to check if fully sent (#28432)
Browse files Browse the repository at this point in the history
* Fix win_write to check if fully sent

* Update tcp_windows.cc

* Update tcp_windows.cc
  • Loading branch information
qbx2 authored and wanlin31 committed May 18, 2023
1 parent 98add7f commit 1355de7
Showing 1 changed file with 37 additions and 15 deletions.
52 changes: 37 additions & 15 deletions src/core/lib/iomgr/tcp_windows.cc
Expand Up @@ -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);
}
}

Expand All @@ -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;
Expand Down Expand Up @@ -391,27 +391,49 @@ 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");

/* 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) {
Expand Down

0 comments on commit 1355de7

Please sign in to comment.