commit 85ed81bb94ca59da49a128cb6ee5065b130ba06c (tree)
parent dd8de03720588eaaa165da70295e29dd23fe1886
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sun, 8 Mar 2026 16:12:37 -0700
std.Io.Threaded: implement netReceive for Windows
Diffstat:
2 files changed, 78 insertions(+), 12 deletions(-)
diff --git 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
@@ -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 = .{},