mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #6838 from LemonBoy/netstuff
std: Add basic smoke test for net functionality
This commit is contained in:
commit
3a0e8c2b45
@ -150,8 +150,8 @@ pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint
|
||||
pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
|
||||
pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
|
||||
pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
|
||||
pub extern "c" fn accept(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) c_int;
|
||||
pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;
|
||||
pub extern "c" fn accept(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t) c_int;
|
||||
pub extern "c" fn accept4(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t, flags: c_uint) c_int;
|
||||
pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int;
|
||||
pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int;
|
||||
pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;
|
||||
|
||||
@ -11,11 +11,7 @@ const mem = std.mem;
|
||||
const os = std.os;
|
||||
const fs = std.fs;
|
||||
|
||||
test "" {
|
||||
_ = @import("net/test.zig");
|
||||
}
|
||||
|
||||
const has_unix_sockets = @hasDecl(os, "sockaddr_un");
|
||||
pub const has_unix_sockets = @hasDecl(os, "sockaddr_un");
|
||||
|
||||
pub const Address = extern union {
|
||||
any: os.sockaddr,
|
||||
@ -610,7 +606,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
|
||||
os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block,
|
||||
0,
|
||||
);
|
||||
errdefer os.close(sockfd);
|
||||
errdefer os.closeSocket(sockfd);
|
||||
|
||||
var addr = try std.net.Address.initUnix(path);
|
||||
|
||||
@ -629,7 +625,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
|
||||
fn if_nametoindex(name: []const u8) !u32 {
|
||||
var ifr: os.ifreq = undefined;
|
||||
var sockfd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM | os.SOCK_CLOEXEC, 0);
|
||||
defer os.close(sockfd);
|
||||
defer os.closeSocket(sockfd);
|
||||
|
||||
std.mem.copy(u8, &ifr.ifrn.name, name);
|
||||
ifr.ifrn.name[name.len] = 0;
|
||||
@ -677,7 +673,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
|
||||
const sock_flags = os.SOCK_STREAM | nonblock |
|
||||
(if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
|
||||
const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
|
||||
errdefer os.close(sockfd);
|
||||
errdefer os.closeSocket(sockfd);
|
||||
|
||||
if (std.io.is_async) {
|
||||
const loop = std.event.Loop.instance orelse return error.WouldBlock;
|
||||
@ -912,7 +908,7 @@ fn linuxLookupName(
|
||||
var prefixlen: i32 = 0;
|
||||
const sock_flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC;
|
||||
if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO_UDP)) |fd| syscalls: {
|
||||
defer os.close(fd);
|
||||
defer os.closeSocket(fd);
|
||||
os.connect(fd, da, dalen) catch break :syscalls;
|
||||
key |= DAS_USABLE;
|
||||
os.getsockname(fd, sa, &salen) catch break :syscalls;
|
||||
@ -1392,7 +1388,7 @@ fn resMSendRc(
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
defer os.close(fd);
|
||||
defer os.closeSocket(fd);
|
||||
try os.bind(fd, &sa.any, sl);
|
||||
|
||||
// Past this point, there are no errors. Each individual query will
|
||||
@ -1546,16 +1542,14 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
|
||||
if (data.len != 4) return error.InvalidDnsARecord;
|
||||
const new_addr = try ctx.addrs.addOne();
|
||||
new_addr.* = LookupAddr{
|
||||
// TODO slice [0..4] to make this *[4]u8 without @ptrCast
|
||||
.addr = Address.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port),
|
||||
.addr = Address.initIp4(data[0..4].*, ctx.port),
|
||||
};
|
||||
},
|
||||
os.RR_AAAA => {
|
||||
if (data.len != 16) return error.InvalidDnsAAAARecord;
|
||||
const new_addr = try ctx.addrs.addOne();
|
||||
new_addr.* = LookupAddr{
|
||||
// TODO slice [0..16] to make this *[16]u8 without @ptrCast
|
||||
.addr = Address.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0),
|
||||
.addr = Address.initIp6(data[0..16].*, ctx.port, 0, 0),
|
||||
};
|
||||
},
|
||||
os.RR_CNAME => {
|
||||
@ -1579,7 +1573,7 @@ pub const StreamServer = struct {
|
||||
/// `undefined` until `listen` returns successfully.
|
||||
listen_address: Address,
|
||||
|
||||
sockfd: ?os.fd_t,
|
||||
sockfd: ?os.socket_t,
|
||||
|
||||
pub const Options = struct {
|
||||
/// How many connections the kernel will accept on the application's behalf.
|
||||
@ -1616,13 +1610,13 @@ pub const StreamServer = struct {
|
||||
const sockfd = try os.socket(address.any.family, sock_flags, proto);
|
||||
self.sockfd = sockfd;
|
||||
errdefer {
|
||||
os.close(sockfd);
|
||||
os.closeSocket(sockfd);
|
||||
self.sockfd = null;
|
||||
}
|
||||
|
||||
if (self.reuse_address) {
|
||||
try os.setsockopt(
|
||||
self.sockfd.?,
|
||||
sockfd,
|
||||
os.SOL_SOCKET,
|
||||
os.SO_REUSEADDR,
|
||||
&mem.toBytes(@as(c_int, 1)),
|
||||
@ -1640,7 +1634,7 @@ pub const StreamServer = struct {
|
||||
/// not listening.
|
||||
pub fn close(self: *StreamServer) void {
|
||||
if (self.sockfd) |fd| {
|
||||
os.close(fd);
|
||||
os.closeSocket(fd);
|
||||
self.sockfd = null;
|
||||
self.listen_address = undefined;
|
||||
}
|
||||
@ -1670,6 +1664,14 @@ pub const StreamServer = struct {
|
||||
/// Permission to create a socket of the specified type and/or
|
||||
/// protocol is denied.
|
||||
PermissionDenied,
|
||||
|
||||
FileDescriptorNotASocket,
|
||||
|
||||
ConnectionResetByPeer,
|
||||
|
||||
NetworkSubsystemFailed,
|
||||
|
||||
OperationNotSupported,
|
||||
} || os.UnexpectedError;
|
||||
|
||||
pub const Connection = struct {
|
||||
@ -1701,3 +1703,7 @@ pub const StreamServer = struct {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test "" {
|
||||
_ = @import("net/test.zig");
|
||||
}
|
||||
|
||||
@ -95,22 +95,81 @@ test "parse and render IPv4 addresses" {
|
||||
}
|
||||
|
||||
test "resolve DNS" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
if (std.builtin.os.tag == .windows) {
|
||||
_ = try std.os.windows.WSAStartup(2, 2);
|
||||
}
|
||||
if (builtin.os.tag == .wasi) {
|
||||
// DNS resolution not implemented on Windows yet.
|
||||
return error.SkipZigTest;
|
||||
defer {
|
||||
if (std.builtin.os.tag == .windows) {
|
||||
std.os.windows.WSACleanup() catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
const address_list = net.getAddressList(testing.allocator, "example.com", 80) catch |err| switch (err) {
|
||||
// Resolve localhost, this should not fail.
|
||||
{
|
||||
const localhost_v4 = try net.Address.parseIp("127.0.0.1", 80);
|
||||
const localhost_v6 = try net.Address.parseIp("::2", 80);
|
||||
|
||||
const result = try net.getAddressList(testing.allocator, "localhost", 80);
|
||||
defer result.deinit();
|
||||
for (result.addrs) |addr| {
|
||||
if (addr.eql(localhost_v4) or addr.eql(localhost_v6)) break;
|
||||
} else @panic("unexpected address for localhost");
|
||||
}
|
||||
|
||||
{
|
||||
// The tests are required to work even when there is no Internet connection,
|
||||
// so some of these errors we must accept and skip the test.
|
||||
error.UnknownHostName => return error.SkipZigTest,
|
||||
error.TemporaryNameServerFailure => return error.SkipZigTest,
|
||||
else => return err,
|
||||
const result = net.getAddressList(testing.allocator, "example.com", 80) catch |err| switch (err) {
|
||||
error.UnknownHostName => return error.SkipZigTest,
|
||||
error.TemporaryNameServerFailure => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
result.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
if (std.builtin.os.tag == .windows) {
|
||||
_ = try std.os.windows.WSAStartup(2, 2);
|
||||
}
|
||||
defer {
|
||||
if (std.builtin.os.tag == .windows) {
|
||||
std.os.windows.WSACleanup() catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
// Try only the IPv4 variant as some CI builders have no IPv6 localhost
|
||||
// configured.
|
||||
const localhost = try net.Address.parseIp("127.0.0.1", 8080);
|
||||
|
||||
var server = net.StreamServer.init(.{});
|
||||
defer server.deinit();
|
||||
|
||||
try server.listen(localhost);
|
||||
|
||||
const S = struct {
|
||||
fn clientFn(server_address: net.Address) !void {
|
||||
const socket = try net.tcpConnectToAddress(server_address);
|
||||
defer socket.close();
|
||||
|
||||
_ = try socket.writer().writeAll("Hello world!");
|
||||
}
|
||||
};
|
||||
address_list.deinit();
|
||||
|
||||
const t = try std.Thread.spawn(server.listen_address, S.clientFn);
|
||||
defer t.wait();
|
||||
|
||||
var client = try server.accept();
|
||||
var buf: [16]u8 = undefined;
|
||||
const n = try client.file.reader().read(&buf);
|
||||
|
||||
testing.expectEqual(@as(usize, 12), n);
|
||||
testing.expectEqualSlices(u8, "Hello world!", buf[0..n]);
|
||||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
|
||||
@ -2687,6 +2687,14 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closeSocket(sock: socket_t) void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
windows.closesocket(sock) catch unreachable;
|
||||
} else {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
pub const BindError = error{
|
||||
/// The address is protected, and the user is not the superuser.
|
||||
/// For UNIX domain sockets: Search permission is denied on a component
|
||||
@ -2731,8 +2739,8 @@ pub const BindError = error{
|
||||
|
||||
/// addr is `*const T` where T is one of the sockaddr
|
||||
pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void {
|
||||
const rc = system.bind(sock, addr, len);
|
||||
if (builtin.os.tag == .windows) {
|
||||
const rc = windows.bind(sock, addr, len);
|
||||
if (rc == windows.ws2_32.SOCKET_ERROR) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSANOTINITIALISED => unreachable, // not initialized WSA
|
||||
@ -2750,6 +2758,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
const rc = system.bind(sock, addr, len);
|
||||
switch (errno(rc)) {
|
||||
0 => return,
|
||||
EACCES => return error.AccessDenied,
|
||||
@ -2800,8 +2809,8 @@ const ListenError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
|
||||
const rc = system.listen(sock, backlog);
|
||||
if (builtin.os.tag == .windows) {
|
||||
const rc = windows.listen(sock, backlog);
|
||||
if (rc == windows.ws2_32.SOCKET_ERROR) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSANOTINITIALISED => unreachable, // not initialized WSA
|
||||
@ -2818,6 +2827,7 @@ pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
const rc = system.listen(sock, backlog);
|
||||
switch (errno(rc)) {
|
||||
0 => return,
|
||||
EADDRINUSE => return error.AddressInUse,
|
||||
@ -2905,6 +2915,8 @@ pub fn accept(
|
||||
const accepted_sock = while (true) {
|
||||
const rc = if (have_accept4)
|
||||
system.accept4(sock, addr, addr_size, flags)
|
||||
else if (builtin.os.tag == .windows)
|
||||
windows.accept(sock, addr, addr_size)
|
||||
else
|
||||
system.accept(sock, addr, addr_size);
|
||||
|
||||
@ -3077,8 +3089,8 @@ pub const GetSockNameError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
|
||||
const rc = system.getsockname(sock, addr, addrlen);
|
||||
if (builtin.os.tag == .windows) {
|
||||
const rc = windows.getsockname(sock, addr, addrlen);
|
||||
if (rc == windows.ws2_32.SOCKET_ERROR) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSANOTINITIALISED => unreachable,
|
||||
@ -3091,6 +3103,7 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
const rc = system.getsockname(sock, addr, addrlen);
|
||||
switch (errno(rc)) {
|
||||
0 => return,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
@ -5378,22 +5391,41 @@ pub const SetSockOptError = error{
|
||||
|
||||
/// Insufficient resources are available in the system to complete the call.
|
||||
SystemResources,
|
||||
|
||||
NetworkSubsystemFailed,
|
||||
FileDescriptorNotASocket,
|
||||
SocketNotBound,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Set a socket's options.
|
||||
pub fn setsockopt(fd: fd_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
|
||||
switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {
|
||||
0 => {},
|
||||
EBADF => unreachable, // always a race condition
|
||||
ENOTSOCK => unreachable, // always a race condition
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EDOM => return error.TimeoutTooBig,
|
||||
EISCONN => return error.AlreadyConnected,
|
||||
ENOPROTOOPT => return error.InvalidProtocolOption,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const rc = windows.ws2_32.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len));
|
||||
if (rc == windows.ws2_32.SOCKET_ERROR) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSANOTINITIALISED => unreachable,
|
||||
.WSAENETDOWN => return error.NetworkSubsystemFailed,
|
||||
.WSAEFAULT => unreachable,
|
||||
.WSAENOTSOCK => return error.FileDescriptorNotASocket,
|
||||
.WSAEINVAL => return error.SocketNotBound,
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {
|
||||
0 => {},
|
||||
EBADF => unreachable, // always a race condition
|
||||
ENOTSOCK => unreachable, // always a race condition
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EDOM => return error.TimeoutTooBig,
|
||||
EISCONN => return error.AlreadyConnected,
|
||||
ENOPROTOOPT => return error.InvalidProtocolOption,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -256,6 +256,41 @@ pub const POLLERR = ws2_32.POLLERR;
|
||||
pub const POLLHUP = ws2_32.POLLHUP;
|
||||
pub const POLLNVAL = ws2_32.POLLNVAL;
|
||||
|
||||
pub const SOL_SOCKET = ws2_32.SOL_SOCKET;
|
||||
|
||||
pub const SO_DEBUG = ws2_32.SO_DEBUG;
|
||||
pub const SO_ACCEPTCONN = ws2_32.SO_ACCEPTCONN;
|
||||
pub const SO_REUSEADDR = ws2_32.SO_REUSEADDR;
|
||||
pub const SO_KEEPALIVE = ws2_32.SO_KEEPALIVE;
|
||||
pub const SO_DONTROUTE = ws2_32.SO_DONTROUTE;
|
||||
pub const SO_BROADCAST = ws2_32.SO_BROADCAST;
|
||||
pub const SO_USELOOPBACK = ws2_32.SO_USELOOPBACK;
|
||||
pub const SO_LINGER = ws2_32.SO_LINGER;
|
||||
pub const SO_OOBINLINE = ws2_32.SO_OOBINLINE;
|
||||
|
||||
pub const SO_DONTLINGER = ws2_32.SO_DONTLINGER;
|
||||
pub const SO_EXCLUSIVEADDRUSE = ws2_32.SO_EXCLUSIVEADDRUSE;
|
||||
|
||||
pub const SO_SNDBUF = ws2_32.SO_SNDBUF;
|
||||
pub const SO_RCVBUF = ws2_32.SO_RCVBUF;
|
||||
pub const SO_SNDLOWAT = ws2_32.SO_SNDLOWAT;
|
||||
pub const SO_RCVLOWAT = ws2_32.SO_RCVLOWAT;
|
||||
pub const SO_SNDTIMEO = ws2_32.SO_SNDTIMEO;
|
||||
pub const SO_RCVTIMEO = ws2_32.SO_RCVTIMEO;
|
||||
pub const SO_ERROR = ws2_32.SO_ERROR;
|
||||
pub const SO_TYPE = ws2_32.SO_TYPE;
|
||||
|
||||
pub const SO_GROUP_ID = ws2_32.SO_GROUP_ID;
|
||||
pub const SO_GROUP_PRIORITY = ws2_32.SO_GROUP_PRIORITY;
|
||||
pub const SO_MAX_MSG_SIZE = ws2_32.SO_MAX_MSG_SIZE;
|
||||
pub const SO_PROTOCOL_INFOA = ws2_32.SO_PROTOCOL_INFOA;
|
||||
pub const SO_PROTOCOL_INFOW = ws2_32.SO_PROTOCOL_INFOW;
|
||||
|
||||
pub const PVD_CONFIG = ws2_32.PVD_CONFIG;
|
||||
pub const SO_CONDITIONAL_ACCEPT = ws2_32.SO_CONDITIONAL_ACCEPT;
|
||||
|
||||
pub const TCP_NODELAY = ws2_32.TCP_NODELAY;
|
||||
|
||||
pub const O_RDONLY = 0o0;
|
||||
pub const O_WRONLY = 0o1;
|
||||
pub const O_RDWR = 0o2;
|
||||
|
||||
@ -1003,14 +1003,14 @@ pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usiz
|
||||
return syscall4(.socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
|
||||
}
|
||||
|
||||
pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
|
||||
pub fn accept(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t) usize {
|
||||
if (builtin.arch == .i386) {
|
||||
return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 });
|
||||
}
|
||||
return accept4(fd, addr, len, 0);
|
||||
}
|
||||
|
||||
pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
|
||||
pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flags: u32) usize {
|
||||
if (builtin.arch == .i386) {
|
||||
return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags });
|
||||
}
|
||||
@ -1279,7 +1279,7 @@ pub fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: ?*const rlimit,
|
||||
@bitCast(usize, @as(isize, pid)),
|
||||
@bitCast(usize, @as(isize, @enumToInt(resource))),
|
||||
@ptrToInt(new_limit),
|
||||
@ptrToInt(old_limit)
|
||||
@ptrToInt(old_limit),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -594,7 +594,7 @@ test "fsync" {
|
||||
|
||||
test "getrlimit and setrlimit" {
|
||||
// TODO enable for other systems when implemented
|
||||
if(builtin.os.tag != .linux){
|
||||
if (builtin.os.tag != .linux) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
|
||||
@ -718,6 +718,41 @@ const IOC_WS2 = 0x08000000;
|
||||
|
||||
pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;
|
||||
|
||||
pub const SOL_SOCKET = 0xffff;
|
||||
|
||||
pub const SO_DEBUG = 0x0001;
|
||||
pub const SO_ACCEPTCONN = 0x0002;
|
||||
pub const SO_REUSEADDR = 0x0004;
|
||||
pub const SO_KEEPALIVE = 0x0008;
|
||||
pub const SO_DONTROUTE = 0x0010;
|
||||
pub const SO_BROADCAST = 0x0020;
|
||||
pub const SO_USELOOPBACK = 0x0040;
|
||||
pub const SO_LINGER = 0x0080;
|
||||
pub const SO_OOBINLINE = 0x0100;
|
||||
|
||||
pub const SO_DONTLINGER = ~@as(u32, SO_LINGER);
|
||||
pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR);
|
||||
|
||||
pub const SO_SNDBUF = 0x1001;
|
||||
pub const SO_RCVBUF = 0x1002;
|
||||
pub const SO_SNDLOWAT = 0x1003;
|
||||
pub const SO_RCVLOWAT = 0x1004;
|
||||
pub const SO_SNDTIMEO = 0x1005;
|
||||
pub const SO_RCVTIMEO = 0x1006;
|
||||
pub const SO_ERROR = 0x1007;
|
||||
pub const SO_TYPE = 0x1008;
|
||||
|
||||
pub const SO_GROUP_ID = 0x2001;
|
||||
pub const SO_GROUP_PRIORITY = 0x2002;
|
||||
pub const SO_MAX_MSG_SIZE = 0x2003;
|
||||
pub const SO_PROTOCOL_INFOA = 0x2004;
|
||||
pub const SO_PROTOCOL_INFOW = 0x2005;
|
||||
|
||||
pub const PVD_CONFIG = 0x3001;
|
||||
pub const SO_CONDITIONAL_ACCEPT = 0x3002;
|
||||
|
||||
pub const TCP_NODELAY = 0x0001;
|
||||
|
||||
pub extern "ws2_32" fn WSAStartup(
|
||||
wVersionRequired: WORD,
|
||||
lpWSAData: *WSADATA,
|
||||
@ -835,3 +870,10 @@ pub extern "ws2_32" fn getsockname(
|
||||
name: *sockaddr,
|
||||
namelen: *c_int,
|
||||
) callconv(.Stdcall) c_int;
|
||||
pub extern "ws2_32" fn setsockopt(
|
||||
s: SOCKET,
|
||||
level: u32,
|
||||
optname: u32,
|
||||
optval: ?*const c_void,
|
||||
optlen: socklen_t,
|
||||
) callconv(.Stdcall) c_int;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user