authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-26 12:05:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
logfd7475c8b2e4ee0d3a12f8517720facc407379b5
tree1e72d9876fb77b7ffdf9a05c5948745252d8edb7
parent6cff32c7ee5be4e10ea768a20c724e348fc90ba3

std.Io.Threaded: implement netWrite for Windows


1 files changed, 95 insertions(+), 8 deletions(-)

lib/std/Io/Threaded.zig+95-8
......@@ -3909,8 +3909,7 @@ fn netSendOne(
39093909 .ENETRESET => return error.ConnectionResetByPeer,
39103910 .ENETUNREACH => return error.NetworkUnreachable,
39113911 .ENOTCONN => return error.SocketUnconnected,
3912 .ESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH.
3913 .NOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
3912 .ESHUTDOWN => |err| return wsaErrorBug(err),
39143913 else => |err| return windows.unexpectedWSAError(err),
39153914 }
39163915 } else {
......@@ -4275,12 +4274,100 @@ fn netWriteWindows(
42754274 splat: usize,
42764275) net.Stream.Writer.Error!usize {
42774276 const t: *Threaded = @ptrCast(@alignCast(userdata));
4278 _ = t;
4279 _ = handle;
4280 _ = header;
4281 _ = data;
4282 _ = splat;
4283 @panic("TODO implement netWriteWindows");
4277 comptime assert(native_os == .windows);
4278
4279 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
4280 var len: u32 = 0;
4281 addWsaBuf(&iovecs, &len, header);
4282 for (data[0 .. data.len - 1]) |bytes| addWsaBuf(&iovecs, &len, bytes);
4283 const pattern = data[data.len - 1];
4284 if (iovecs.len - len != 0) switch (splat) {
4285 0 => {},
4286 1 => addWsaBuf(&iovecs, &len, pattern),
4287 else => switch (pattern.len) {
4288 0 => {},
4289 1 => {
4290 var backup_buffer: [64]u8 = undefined;
4291 const splat_buffer = &backup_buffer;
4292 const memset_len = @min(splat_buffer.len, splat);
4293 const buf = splat_buffer[0..memset_len];
4294 @memset(buf, pattern[0]);
4295 addWsaBuf(&iovecs, &len, buf);
4296 var remaining_splat = splat - buf.len;
4297 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
4298 addWsaBuf(&iovecs, &len, splat_buffer);
4299 remaining_splat -= splat_buffer.len;
4300 }
4301 addWsaBuf(&iovecs, &len, splat_buffer[0..remaining_splat]);
4302 },
4303 else => for (0..@min(splat, iovecs.len - len)) |_| {
4304 addWsaBuf(&iovecs, &len, pattern);
4305 },
4306 },
4307 };
4308
4309 while (true) {
4310 try t.checkCancel();
4311
4312 var n: u32 = undefined;
4313 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
4314 const rc = ws2_32.WSASend(handle, &iovecs, len, &n, 0, &overlapped, null);
4315 if (rc != ws2_32.SOCKET_ERROR) return n;
4316 const wsa_error: ws2_32.WinsockError = switch (ws2_32.WSAGetLastError()) {
4317 .IO_PENDING => e: {
4318 var result_flags: u32 = undefined;
4319 const overlapped_rc = ws2_32.WSAGetOverlappedResult(
4320 handle,
4321 &overlapped,
4322 &n,
4323 windows.TRUE,
4324 &result_flags,
4325 );
4326 if (overlapped_rc == windows.FALSE) {
4327 break :e ws2_32.WSAGetLastError();
4328 } else {
4329 return n;
4330 }
4331 },
4332 else => |err| err,
4333 };
4334 switch (wsa_error) {
4335 .EINTR => continue,
4336 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4337 .NOTINITIALISED => {
4338 try initializeWsa(t);
4339 continue;
4340 },
4341
4342 .ECONNABORTED => return error.ConnectionResetByPeer,
4343 .ECONNRESET => return error.ConnectionResetByPeer,
4344 .EINVAL => return error.SocketUnconnected,
4345 .ENETDOWN => return error.NetworkDown,
4346 .ENETRESET => return error.ConnectionResetByPeer,
4347 .ENOBUFS => return error.SystemResources,
4348 .ENOTCONN => return error.SocketUnconnected,
4349 .ENOTSOCK => |err| return wsaErrorBug(err),
4350 .EOPNOTSUPP => |err| return wsaErrorBug(err),
4351 .ESHUTDOWN => |err| return wsaErrorBug(err),
4352 else => |err| return windows.unexpectedWSAError(err),
4353 }
4354 }
4355}
4356
4357fn addWsaBuf(v: []ws2_32.WSABUF, i: *u32, bytes: []const u8) void {
4358 const cap = std.math.maxInt(u32);
4359 var remaining = bytes;
4360 while (remaining.len > cap) {
4361 if (v.len - i.* == 0) return;
4362 v[i.*] = .{ .buf = @constCast(remaining.ptr), .len = cap };
4363 i.* += 1;
4364 remaining = remaining[cap..];
4365 } else {
4366 @branchHint(.likely);
4367 if (v.len - i.* == 0) return;
4368 v[i.*] = .{ .buf = @constCast(remaining.ptr), .len = @intCast(remaining.len) };
4369 i.* += 1;
4370 }
42844371}
42854372
42864373fn netWriteUnavailable(