std.Io.Threaded: implement netBindIp for Windows

This commit is contained in:
Andrew Kelley 2025-10-20 22:59:05 -07:00
parent 0b5179a231
commit 76107e9e65

View file

@ -248,7 +248,7 @@ pub fn io(t: *Threaded) Io {
else => netAcceptPosix, else => netAcceptPosix,
}, },
.netBindIp = switch (builtin.os.tag) { .netBindIp = switch (builtin.os.tag) {
.windows => @panic("TODO"), .windows => netBindIpWindows,
else => netBindIpPosix, else => netBindIpPosix,
}, },
.netConnectIp = switch (builtin.os.tag) { .netConnectIp = switch (builtin.os.tag) {
@ -2828,7 +2828,7 @@ fn netListenIpWindows(
.EAFNOSUPPORT => return error.AddressFamilyUnsupported, .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
.EMFILE => return error.ProcessFdQuotaExceeded, .EMFILE => return error.ProcessFdQuotaExceeded,
.ENOBUFS => return error.SystemResources, .ENOBUFS => return error.SystemResources,
.EPROTONOSUPPORT => return error.ProtocolUnsupportedBySystem, .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
else => |err| return windows.unexpectedWSAError(err), else => |err| return windows.unexpectedWSAError(err),
} }
}; };
@ -3176,6 +3176,86 @@ fn netBindIpPosix(
}; };
} }
fn netBindIpWindows(
userdata: ?*anyopaque,
address: *const IpAddress,
options: IpAddress.BindOptions,
) IpAddress.BindError!net.Socket {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
const family = posixAddressFamily(address);
const mode = posixSocketMode(options.mode);
const protocol = posixProtocol(options.protocol);
const socket_handle = while (true) {
try t.checkCancel();
const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
if (rc != ws2_32.INVALID_SOCKET) break rc;
switch (ws2_32.WSAGetLastError()) {
.EINTR => continue,
.ECANCELLED, .E_CANCELLED => return error.Canceled,
.NOTINITIALISED => {
try initializeWsa(t);
continue;
},
.EAFNOSUPPORT => return error.AddressFamilyUnsupported,
.EMFILE => return error.ProcessFdQuotaExceeded,
.ENOBUFS => return error.SystemResources,
.EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
else => |err| return windows.unexpectedWSAError(err),
}
};
errdefer closeSocketWindows(socket_handle);
var storage: WsaAddress = undefined;
var addr_len = addressToWsa(address, &storage);
while (true) {
try t.checkCancel();
const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
if (rc != ws2_32.SOCKET_ERROR) break;
switch (ws2_32.WSAGetLastError()) {
.EINTR => continue,
.ECANCELLED, .E_CANCELLED => return error.Canceled,
.NOTINITIALISED => {
try initializeWsa(t);
continue;
},
.EADDRINUSE => return error.AddressInUse,
.EADDRNOTAVAIL => return error.AddressUnavailable,
.ENOTSOCK => |err| return wsaErrorBug(err),
.EFAULT => |err| return wsaErrorBug(err),
.EINVAL => |err| return wsaErrorBug(err),
.ENOBUFS => return error.SystemResources,
.ENETDOWN => return error.NetworkDown,
else => |err| return windows.unexpectedWSAError(err),
}
}
while (true) {
try t.checkCancel();
const rc = ws2_32.getsockname(socket_handle, &storage.any, &addr_len);
if (rc != ws2_32.SOCKET_ERROR) break;
switch (ws2_32.WSAGetLastError()) {
.EINTR => continue,
.ECANCELLED, .E_CANCELLED => return error.Canceled,
.NOTINITIALISED => {
try initializeWsa(t);
continue;
},
.ENETDOWN => return error.NetworkDown,
.EFAULT => |err| return wsaErrorBug(err),
.ENOTSOCK => |err| return wsaErrorBug(err),
.EINVAL => |err| return wsaErrorBug(err),
else => |err| return windows.unexpectedWSAError(err),
}
}
return .{
.handle = socket_handle,
.address = addressFromWsa(&storage),
};
}
fn openSocketPosix( fn openSocketPosix(
t: *Threaded, t: *Threaded,
family: posix.sa_family_t, family: posix.sa_family_t,