mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
std.Io.Threaded: implement netConnectIp for Windows
This commit is contained in:
parent
67df66c26c
commit
4ed74a9f8a
@ -252,7 +252,7 @@ pub fn io(t: *Threaded) Io {
|
|||||||
else => netBindIpPosix,
|
else => netBindIpPosix,
|
||||||
},
|
},
|
||||||
.netConnectIp = switch (builtin.os.tag) {
|
.netConnectIp = switch (builtin.os.tag) {
|
||||||
.windows => @panic("TODO"),
|
.windows => netConnectIpWindows,
|
||||||
else => netConnectIpPosix,
|
else => netConnectIpPosix,
|
||||||
},
|
},
|
||||||
.netConnectUnix = netConnectUnix,
|
.netConnectUnix = netConnectUnix,
|
||||||
@ -2810,28 +2810,10 @@ fn netListenIpWindows(
|
|||||||
if (!have_networking) return error.NetworkDown;
|
if (!have_networking) return error.NetworkDown;
|
||||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||||
const family = posixAddressFamily(&address);
|
const family = posixAddressFamily(&address);
|
||||||
const mode = posixSocketMode(options.mode);
|
const socket_handle = try openSocketWsa(t, family, .{
|
||||||
const protocol = posixProtocol(options.protocol);
|
.mode = options.mode,
|
||||||
|
.protocol = 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);
|
errdefer closeSocketWindows(socket_handle);
|
||||||
|
|
||||||
if (options.reuse_address)
|
if (options.reuse_address)
|
||||||
@ -2885,24 +2867,7 @@ fn netListenIpWindows(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
|
||||||
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 .{
|
return .{
|
||||||
.socket = .{
|
.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 {
|
fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
|
||||||
const o: []const u8 = @ptrCast(&option);
|
const o: []const u8 = @ptrCast(&option);
|
||||||
while (true) {
|
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(
|
fn netConnectUnix(
|
||||||
userdata: ?*anyopaque,
|
userdata: ?*anyopaque,
|
||||||
address: *const net.UnixAddress,
|
address: *const net.UnixAddress,
|
||||||
@ -3184,28 +3225,12 @@ fn netBindIpWindows(
|
|||||||
if (!have_networking) return error.NetworkDown;
|
if (!have_networking) return error.NetworkDown;
|
||||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||||
const family = posixAddressFamily(address);
|
const family = posixAddressFamily(address);
|
||||||
const mode = posixSocketMode(options.mode);
|
const socket_handle = try openSocketWsa(t, family, .{
|
||||||
const protocol = posixProtocol(options.protocol);
|
.mode = options.mode,
|
||||||
const socket_handle = while (true) {
|
.protocol = options.protocol,
|
||||||
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);
|
errdefer closeSocketWindows(socket_handle);
|
||||||
|
|
||||||
var storage: WsaAddress = undefined;
|
var storage: WsaAddress = undefined;
|
||||||
var addr_len = addressToWsa(address, &storage);
|
var addr_len = addressToWsa(address, &storage);
|
||||||
|
|
||||||
@ -3231,24 +3256,7 @@ fn netBindIpWindows(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
|
||||||
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 .{
|
return .{
|
||||||
.handle = socket_handle,
|
.handle = socket_handle,
|
||||||
@ -3317,6 +3325,30 @@ fn openSocketPosix(
|
|||||||
return socket_fd;
|
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 {
|
fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
|
||||||
if (!have_networking) return error.NetworkDown;
|
if (!have_networking) return error.NetworkDown;
|
||||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||||
@ -3376,11 +3408,11 @@ fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net
|
|||||||
while (true) {
|
while (true) {
|
||||||
try t.checkCancel();
|
try t.checkCancel();
|
||||||
const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
|
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,
|
.handle = rc,
|
||||||
.address = addressFromWsa(&storage),
|
.address = addressFromWsa(&storage),
|
||||||
} };
|
} };
|
||||||
switch (windows.ws2_32.WSAGetLastError()) {
|
switch (ws2_32.WSAGetLastError()) {
|
||||||
.EINTR => continue,
|
.EINTR => continue,
|
||||||
.ECANCELLED, .E_CANCELLED => return error.Canceled,
|
.ECANCELLED, .E_CANCELLED => return error.Canceled,
|
||||||
.NOTINITIALISED => {
|
.NOTINITIALISED => {
|
||||||
|
|||||||
@ -3757,86 +3757,11 @@ pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ConnectError = error{
|
pub const ConnectError = std.Io.net.IpAddress.ConnectError || std.Io.net.UnixAddress.ConnectError;
|
||||||
/// 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,
|
|
||||||
|
|
||||||
/// 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 {
|
pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
const rc = windows.ws2_32.connect(sock, sock_addr, @intCast(len));
|
@compileError("use std.Io instead");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user