more windows network fixes
* support posix SOCK_NONBLOCK and SOCK_CLOEXEC flags on windows * fix bugs in os.socket and os.connect to return at the correct placemaster
parent
2bae91e769
commit
58fb5b29b6
|
@ -452,37 +452,33 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
|
|||
};
|
||||
var res: *os.addrinfo = undefined;
|
||||
const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res);
|
||||
if (builtin.os.tag == .windows) {
|
||||
const ws2_32 = os.windows.ws2_32;
|
||||
if (rc != 0) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
|
||||
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
|
||||
.WSANO_RECOVERY => return error.NameServerFailure,
|
||||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
|
||||
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
|
||||
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
|
||||
.WSAEINVAL => unreachable,
|
||||
.WSAESOCKTNOSUPPORT => unreachable,
|
||||
else => |err| return os.windows.unexpectedWSAError(err),
|
||||
};
|
||||
} else {
|
||||
switch (rc) {
|
||||
@intToEnum(sys.EAI, 0) => {},
|
||||
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
|
||||
.AGAIN => return error.TemporaryNameServerFailure,
|
||||
.BADFLAGS => unreachable, // Invalid hints
|
||||
.FAIL => return error.NameServerFailure,
|
||||
.FAMILY => return error.AddressFamilyNotSupported,
|
||||
.MEMORY => return error.OutOfMemory,
|
||||
.NODATA => return error.HostLacksNetworkAddresses,
|
||||
.NONAME => return error.UnknownHostName,
|
||||
.SERVICE => return error.ServiceUnavailable,
|
||||
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
|
||||
.SYSTEM => switch (os.errno(-1)) {
|
||||
else => |e| return os.unexpectedErrno(e),
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
if (builtin.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
|
||||
@intToEnum(os.windows.ws2_32.WinsockError, 0) => {},
|
||||
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
|
||||
.WSANO_RECOVERY => return error.NameServerFailure,
|
||||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
|
||||
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
|
||||
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
|
||||
.WSAEINVAL => unreachable,
|
||||
.WSAESOCKTNOSUPPORT => unreachable,
|
||||
else => |err| return os.windows.unexpectedWSAError(err),
|
||||
} else switch (rc) {
|
||||
@intToEnum(sys.EAI, 0) => {},
|
||||
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
|
||||
.AGAIN => return error.TemporaryNameServerFailure,
|
||||
.BADFLAGS => unreachable, // Invalid hints
|
||||
.FAIL => return error.NameServerFailure,
|
||||
.FAMILY => return error.AddressFamilyNotSupported,
|
||||
.MEMORY => return error.OutOfMemory,
|
||||
.NODATA => return error.HostLacksNetworkAddresses,
|
||||
.NONAME => return error.UnknownHostName,
|
||||
.SERVICE => return error.ServiceUnavailable,
|
||||
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
|
||||
.SYSTEM => switch (os.errno(-1)) {
|
||||
else => |e| return os.unexpectedErrno(e),
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
defer sys.freeaddrinfo(res);
|
||||
|
||||
|
|
|
@ -2447,17 +2447,29 @@ pub const SocketError = error{
|
|||
|
||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// NOTE: cannot remove SOCK_NONBLOCK and SOCK_CLOEXEC from socket_type because
|
||||
// windows does not define this flags yet
|
||||
const rc = windows.ws2_32.socket(@intCast(c_int, domain), @intCast(c_int, socket_type), @intCast(c_int, protocol));
|
||||
if (rc != windows.ws2_32.INVALID_SOCKET) return rc;
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
// NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
|
||||
const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
const flags : u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0;
|
||||
const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type),
|
||||
@intCast(c_int, protocol), null, 0, flags);
|
||||
if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSAEMFILE => return error.ProcessFdQuotaExceeded,
|
||||
.WSAENOBUFS => return error.SystemResources,
|
||||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
.WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
};
|
||||
errdefer windows.closesocket(rc) catch unreachable;
|
||||
if ((socket_type & SOCK_NONBLOCK) != 0) {
|
||||
var mode : c_ulong = 1; // nonblocking
|
||||
if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
// have not identified any error codes that should be handled yet
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
const have_sock_flags = comptime !std.Target.current.isDarwin();
|
||||
|
@ -2855,6 +2867,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
|
|||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
|
|
@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW;
|
|||
pub const SOCK_RDM = ws2_32.SOCK_RDM;
|
||||
pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET;
|
||||
|
||||
/// WARNING: this flag is not supported by windows socket functions directly,
|
||||
/// it is only supported by std.os.socket. Be sure that this value does
|
||||
/// not share any bits with any of the SOCK_* values.
|
||||
pub const SOCK_CLOEXEC = 0x10000;
|
||||
/// WARNING: this flag is not supported by windows socket functions directly,
|
||||
/// it is only supported by std.os.socket. Be sure that this value does
|
||||
/// not share any bits with any of the SOCK_* values.
|
||||
pub const SOCK_NONBLOCK = 0x20000;
|
||||
|
||||
pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP;
|
||||
pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP;
|
||||
pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM;
|
||||
|
|
|
@ -174,6 +174,8 @@ pub const AI_SECURE = 0x08000;
|
|||
pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
|
||||
pub const AI_DISABLE_IDN_ENCODING = 0x80000;
|
||||
|
||||
pub const FIONBIO = -2147195266;
|
||||
|
||||
pub const sockaddr = extern struct {
|
||||
family: ADDRESS_FAMILY,
|
||||
data: [14]u8,
|
||||
|
@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl(
|
|||
lpOverlapped: ?*WSAOVERLAPPED,
|
||||
lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) callconv(.Stdcall) c_int;
|
||||
pub extern "ws2_32" fn socket(
|
||||
af: c_int,
|
||||
type: c_int,
|
||||
protocol: c_int,
|
||||
) callconv(.Stdcall) SOCKET;
|
||||
pub extern "ws2_32" fn accept(
|
||||
s: SOCKET,
|
||||
addr: ?*sockaddr,
|
||||
|
@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo(
|
|||
pub extern "ws2_32" fn freeaddrinfo(
|
||||
pAddrInfo: *addrinfo,
|
||||
) callconv(.Stdcall) void;
|
||||
pub extern "ws2_32" fn ioctlsocket(
|
||||
s: SOCKET,
|
||||
cmd: c_long,
|
||||
argp: *c_ulong,
|
||||
) callconv(.Stdcall) c_int;
|
||||
|
|
Loading…
Reference in New Issue