mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.Io.Threaded: implement netConnectIp for Windows
This commit is contained in:
parent
67df66c26c
commit
4ed74a9f8a
2 changed files with 116 additions and 159 deletions
|
|
@ -252,7 +252,7 @@ pub fn io(t: *Threaded) Io {
|
|||
else => netBindIpPosix,
|
||||
},
|
||||
.netConnectIp = switch (builtin.os.tag) {
|
||||
.windows => @panic("TODO"),
|
||||
.windows => netConnectIpWindows,
|
||||
else => netConnectIpPosix,
|
||||
},
|
||||
.netConnectUnix = netConnectUnix,
|
||||
|
|
@ -2810,28 +2810,10 @@ fn netListenIpWindows(
|
|||
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),
|
||||
}
|
||||
};
|
||||
const socket_handle = try openSocketWsa(t, family, .{
|
||||
.mode = options.mode,
|
||||
.protocol = options.protocol,
|
||||
});
|
||||
errdefer closeSocketWindows(socket_handle);
|
||||
|
||||
if (options.reuse_address)
|
||||
|
|
@ -2885,24 +2867,7 @@ fn netListenIpWindows(
|
|||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
|
||||
|
||||
return .{
|
||||
.socket = .{
|
||||
|
|
@ -3076,6 +3041,27 @@ fn posixGetSockName(t: *Threaded, socket_fd: posix.fd_t, addr: *posix.sockaddr,
|
|||
}
|
||||
}
|
||||
|
||||
fn wsaGetSockName(t: *Threaded, handle: ws2_32.SOCKET, addr: *ws2_32.sockaddr, addr_len: *i32) !void {
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
const rc = ws2_32.getsockname(handle, addr, 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
|
||||
const o: []const u8 = @ptrCast(&option);
|
||||
while (true) {
|
||||
|
|
@ -3139,6 +3125,61 @@ fn netConnectIpPosix(
|
|||
} };
|
||||
}
|
||||
|
||||
fn netConnectIpWindows(
|
||||
userdata: ?*anyopaque,
|
||||
address: *const IpAddress,
|
||||
options: IpAddress.ConnectOptions,
|
||||
) IpAddress.ConnectError!net.Stream {
|
||||
if (!have_networking) return error.NetworkDown;
|
||||
if (options.timeout != .none) @panic("TODO");
|
||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||
const family = posixAddressFamily(address);
|
||||
const socket_handle = try openSocketWsa(t, family, .{
|
||||
.mode = options.mode,
|
||||
.protocol = options.protocol,
|
||||
});
|
||||
errdefer closeSocketWindows(socket_handle);
|
||||
|
||||
var storage: WsaAddress = undefined;
|
||||
var addr_len = addressToWsa(address, &storage);
|
||||
|
||||
while (true) {
|
||||
const rc = ws2_32.connect(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;
|
||||
},
|
||||
|
||||
.EADDRNOTAVAIL => return error.AddressUnavailable,
|
||||
.ECONNREFUSED => return error.ConnectionRefused,
|
||||
.ECONNRESET => return error.ConnectionResetByPeer,
|
||||
.ETIMEDOUT => return error.Timeout,
|
||||
.EHOSTUNREACH => return error.HostUnreachable,
|
||||
.ENETUNREACH => return error.NetworkUnreachable,
|
||||
.EFAULT => |err| return wsaErrorBug(err),
|
||||
.EINVAL => |err| return wsaErrorBug(err),
|
||||
.EISCONN => |err| return wsaErrorBug(err),
|
||||
.ENOTSOCK => |err| return wsaErrorBug(err),
|
||||
.EWOULDBLOCK => return error.WouldBlock,
|
||||
.EACCES => return error.AccessDenied,
|
||||
.ENOBUFS => return error.SystemResources,
|
||||
.EAFNOSUPPORT => return error.AddressFamilyUnsupported,
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
}
|
||||
}
|
||||
|
||||
try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
|
||||
|
||||
return .{ .socket = .{
|
||||
.handle = socket_handle,
|
||||
.address = addressFromWsa(&storage),
|
||||
} };
|
||||
}
|
||||
|
||||
fn netConnectUnix(
|
||||
userdata: ?*anyopaque,
|
||||
address: *const net.UnixAddress,
|
||||
|
|
@ -3184,28 +3225,12 @@ fn netBindIpWindows(
|
|||
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),
|
||||
}
|
||||
};
|
||||
const socket_handle = try openSocketWsa(t, family, .{
|
||||
.mode = options.mode,
|
||||
.protocol = options.protocol,
|
||||
});
|
||||
errdefer closeSocketWindows(socket_handle);
|
||||
|
||||
var storage: WsaAddress = undefined;
|
||||
var addr_len = addressToWsa(address, &storage);
|
||||
|
||||
|
|
@ -3231,24 +3256,7 @@ fn netBindIpWindows(
|
|||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
|
||||
|
||||
return .{
|
||||
.handle = socket_handle,
|
||||
|
|
@ -3317,6 +3325,30 @@ fn openSocketPosix(
|
|||
return socket_fd;
|
||||
}
|
||||
|
||||
fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.BindOptions) !ws2_32.SOCKET {
|
||||
const mode = posixSocketMode(options.mode);
|
||||
const protocol = posixProtocol(options.protocol);
|
||||
const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
|
||||
if (rc != ws2_32.INVALID_SOCKET) return 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
|
||||
if (!have_networking) return error.NetworkDown;
|
||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||
|
|
@ -3376,11 +3408,11 @@ fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net
|
|||
while (true) {
|
||||
try t.checkCancel();
|
||||
const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
|
||||
if (rc != windows.ws2_32.INVALID_SOCKET) return .{ .socket = .{
|
||||
if (rc != ws2_32.INVALID_SOCKET) return .{ .socket = .{
|
||||
.handle = rc,
|
||||
.address = addressFromWsa(&storage),
|
||||
} };
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
switch (ws2_32.WSAGetLastError()) {
|
||||
.EINTR => continue,
|
||||
.ECANCELLED, .E_CANCELLED => return error.Canceled,
|
||||
.NOTINITIALISED => {
|
||||
|
|
|
|||
|
|
@ -3757,86 +3757,11 @@ pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
|
|||
}
|
||||
}
|
||||
|
||||
pub const ConnectError = error{
|
||||
/// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
|
||||
/// file, or search permission is denied for one of the directories in the path prefix.
|
||||
/// or
|
||||
/// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
|
||||
/// the connection request failed because of a local firewall rule.
|
||||
AccessDenied,
|
||||
pub const ConnectError = std.Io.net.IpAddress.ConnectError || std.Io.net.UnixAddress.ConnectError;
|
||||
|
||||
/// See AccessDenied
|
||||
PermissionDenied,
|
||||
|
||||
/// Local address is already in use.
|
||||
AddressInUse,
|
||||
|
||||
/// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
|
||||
/// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
|
||||
/// in the ephemeral port range are currently in use. See the discussion of
|
||||
/// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
|
||||
AddressUnavailable,
|
||||
|
||||
/// The passed address didn't have the correct address family in its sa_family field.
|
||||
AddressFamilyUnsupported,
|
||||
|
||||
/// Insufficient entries in the routing cache.
|
||||
SystemResources,
|
||||
|
||||
/// A connect() on a stream socket found no one listening on the remote address.
|
||||
ConnectionRefused,
|
||||
|
||||
/// Network is unreachable.
|
||||
NetworkUnreachable,
|
||||
|
||||
/// Timeout while attempting connection. The server may be too busy to accept new connections. Note
|
||||
/// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
|
||||
Timeout,
|
||||
|
||||
/// This error occurs when no global event loop is configured,
|
||||
/// and connecting to the socket would block.
|
||||
WouldBlock,
|
||||
|
||||
/// The given path for the unix socket does not exist.
|
||||
FileNotFound,
|
||||
|
||||
/// Connection was reset by peer before connect could complete.
|
||||
ConnectionResetByPeer,
|
||||
|
||||
/// Socket is non-blocking and already has a pending connection in progress.
|
||||
ConnectionPending,
|
||||
|
||||
/// Socket was already connected
|
||||
AlreadyConnected,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Initiate a connection on a socket.
|
||||
/// If `sockfd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.
|
||||
pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
|
||||
if (native_os == .windows) {
|
||||
const rc = windows.ws2_32.connect(sock, sock_addr, @intCast(len));
|
||||
if (rc == 0) return;
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.EADDRINUSE => return error.AddressInUse,
|
||||
.EADDRNOTAVAIL => return error.AddressUnavailable,
|
||||
.ECONNREFUSED => return error.ConnectionRefused,
|
||||
.ECONNRESET => return error.ConnectionResetByPeer,
|
||||
.ETIMEDOUT => return error.Timeout,
|
||||
.EHOSTUNREACH, // TODO: should we return NetworkUnreachable in this case as well?
|
||||
.ENETUNREACH,
|
||||
=> return error.NetworkUnreachable,
|
||||
.EFAULT => unreachable,
|
||||
.EINVAL => unreachable,
|
||||
.EISCONN => return error.AlreadyConnected,
|
||||
.ENOTSOCK => unreachable,
|
||||
.EWOULDBLOCK => return error.WouldBlock,
|
||||
.EACCES => unreachable,
|
||||
.ENOBUFS => return error.SystemResources,
|
||||
.EAFNOSUPPORT => return error.AddressFamilyUnsupported,
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
}
|
||||
return;
|
||||
@compileError("use std.Io instead");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue