diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 1d12f8a55b..81a500e0f9 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -13072,11 +13072,76 @@ fn netSendWindows( ) struct { ?net.Socket.SendError, usize } { if (!have_networking) return .{ error.NetworkDown, 0 }; const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; - _ = handle; - _ = messages; - _ = flags; - @panic("TODO netSendWindows"); + + // Ignored flags: confirm, eor, fastopen + const windows_flags: u32 = + @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) | + @as(u32, if (flags.dont_route) ws2_32.MSG.DONTROUTE else 0); + + for (messages, 0..) |*m, i| { + netSendWindowsOne(t, handle, m, windows_flags) catch |err| return .{ err, i }; + } + return .{ null, messages.len }; +} + +fn netSendWindowsOne( + t: *Threaded, + handle: net.Socket.Handle, + message: *net.OutgoingMessage, + flags: u32, +) net.Socket.SendError!void { + var buf: ws2_32.WSABUF = .{ + .buf = @constCast(message.data_ptr), + .len = std.math.cast(u32, message.data_len) orelse return error.MessageOversize, + }; + var n: u32 = undefined; + var address: WsaAddress = undefined; + const address_size = addressToWsa(message.address, &address); + var syscall: Syscall = try .start(); + while (true) { + const rc = ws2_32.WSASendTo( + handle, + (&buf)[0..1], + 1, + &n, + flags, + &address.any, + address_size, + null, + null, + ); + if (rc != ws2_32.SOCKET_ERROR) { + syscall.finish(); + return; + } + switch (ws2_32.WSAGetLastError()) { + .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { + try syscall.checkCancel(); + continue; + }, + .NOTINITIALISED => { + syscall.finish(); + try initializeWsa(t); + syscall = try .start(); + continue; + }, + + .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), + .ENETDOWN => return syscall.fail(error.NetworkDown), + .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), + .ENOTCONN => return syscall.fail(error.SocketUnconnected), + .EFAULT => unreachable, // a pointer is not completely contained in user address space. + + else => |err| { + syscall.finish(); + switch (err) { + .EINVAL => return wsaErrorBug(err), + .EMSGSIZE => return wsaErrorBug(err), + else => return windows.unexpectedWSAError(err), + } + }, + } + } } fn netSendUnavailable( diff --git a/lib/std/Io/net.zig b/lib/std/Io/net.zig index 7a49996ff8..6d5b11e1b1 100644 --- a/lib/std/Io/net.zig +++ b/lib/std/Io/net.zig @@ -1117,12 +1117,13 @@ pub const Socket = struct { /// * `receiveTimeout` pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage { var message: IncomingMessage = .init; - const maybe_err, const count = io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, .none); - if (maybe_err) |err| switch (err) { - // No timeout is passed to `netReceieve`, so it must not return timeout related errors. - error.Timeout => unreachable, - else => |e| return e, - }; + const maybe_err, const count = (try io.operate(.{ .net_receive = .{ + .socket_handle = s.handle, + .message_buffer = (&message)[0..1], + .data_buffer = buffer, + .flags = .{}, + } })).net_receive; + if (maybe_err) |err| return err; assert(1 == count); return message; } @@ -1144,7 +1145,7 @@ pub const Socket = struct { ) ReceiveTimeoutError!IncomingMessage { var message: IncomingMessage = .init; const maybe_err, const count = (try io.operateTimeout(.{ .net_receive = .{ - .socket = s.handle, + .socket_handle = s.handle, .message_buffer = (&message)[0..1], .data_buffer = buffer, .flags = .{},