diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index 4159362469843..b94c1954f3fe2 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/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) {