Commit 4ed74a9f8a
Changed files (2)
lib
std
lib/std/Io/Threaded.zig
@@ -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 => {
lib/std/posix.zig
@@ -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,
-
- /// 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,
+pub const ConnectError = std.Io.net.IpAddress.ConnectError || std.Io.net.UnixAddress.ConnectError;
- /// 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) {