mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 16:45:27 +00:00
Merge branch 'std.net'
This commit is contained in:
commit
61d5a0bf48
@ -72,11 +72,11 @@ pub const Buffer = struct {
|
||||
self.list.deinit();
|
||||
}
|
||||
|
||||
pub fn toSlice(self: *const Buffer) []u8 {
|
||||
pub fn toSlice(self: Buffer) []u8 {
|
||||
return self.list.toSlice()[0..self.len()];
|
||||
}
|
||||
|
||||
pub fn toSliceConst(self: *const Buffer) []const u8 {
|
||||
pub fn toSliceConst(self: Buffer) []const u8 {
|
||||
return self.list.toSliceConst()[0..self.len()];
|
||||
}
|
||||
|
||||
@ -91,11 +91,11 @@ pub const Buffer = struct {
|
||||
self.list.items[self.len()] = 0;
|
||||
}
|
||||
|
||||
pub fn isNull(self: *const Buffer) bool {
|
||||
pub fn isNull(self: Buffer) bool {
|
||||
return self.list.len == 0;
|
||||
}
|
||||
|
||||
pub fn len(self: *const Buffer) usize {
|
||||
pub fn len(self: Buffer) usize {
|
||||
return self.list.len - 1;
|
||||
}
|
||||
|
||||
@ -111,16 +111,16 @@ pub const Buffer = struct {
|
||||
self.list.toSlice()[old_len] = byte;
|
||||
}
|
||||
|
||||
pub fn eql(self: *const Buffer, m: []const u8) bool {
|
||||
pub fn eql(self: Buffer, m: []const u8) bool {
|
||||
return mem.eql(u8, self.toSliceConst(), m);
|
||||
}
|
||||
|
||||
pub fn startsWith(self: *const Buffer, m: []const u8) bool {
|
||||
pub fn startsWith(self: Buffer, m: []const u8) bool {
|
||||
if (self.len() < m.len) return false;
|
||||
return mem.eql(u8, self.list.items[0..m.len], m);
|
||||
}
|
||||
|
||||
pub fn endsWith(self: *const Buffer, m: []const u8) bool {
|
||||
pub fn endsWith(self: Buffer, m: []const u8) bool {
|
||||
const l = self.len();
|
||||
if (l < m.len) return false;
|
||||
const start = l - m.len;
|
||||
@ -133,7 +133,7 @@ pub const Buffer = struct {
|
||||
}
|
||||
|
||||
/// For passing to C functions.
|
||||
pub fn ptr(self: *const Buffer) [*]u8 {
|
||||
pub fn ptr(self: Buffer) [*]u8 {
|
||||
return self.list.items.ptr;
|
||||
}
|
||||
};
|
||||
|
@ -117,6 +117,26 @@ pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias add
|
||||
pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const 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: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int;
|
||||
pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;
|
||||
pub extern "c" fn sendto(
|
||||
sockfd: fd_t,
|
||||
buf: *const c_void,
|
||||
len: usize,
|
||||
flags: u32,
|
||||
dest_addr: *const sockaddr,
|
||||
addrlen: socklen_t,
|
||||
) isize;
|
||||
|
||||
pub extern fn recv(sockfd: fd_t, arg1: ?*c_void, arg2: usize, arg3: c_int) isize;
|
||||
pub extern fn recvfrom(
|
||||
sockfd: fd_t,
|
||||
noalias buf: *c_void,
|
||||
len: usize,
|
||||
flags: u32,
|
||||
noalias src_addr: ?*sockaddr,
|
||||
noalias addrlen: ?*socklen_t,
|
||||
) isize;
|
||||
|
||||
pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
|
||||
pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;
|
||||
pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
|
||||
@ -149,3 +169,34 @@ pub extern "c" fn kevent(
|
||||
nevents: c_int,
|
||||
timeout: ?*const timespec,
|
||||
) c_int;
|
||||
|
||||
pub extern "c" fn getaddrinfo(
|
||||
noalias node: [*]const u8,
|
||||
noalias service: [*]const u8,
|
||||
noalias hints: *const addrinfo,
|
||||
noalias res: **addrinfo,
|
||||
) c_int;
|
||||
|
||||
pub extern "c" fn freeaddrinfo(res: *addrinfo) void;
|
||||
|
||||
pub extern "c" fn getnameinfo(
|
||||
noalias addr: *const sockaddr,
|
||||
addrlen: socklen_t,
|
||||
noalias host: [*]u8,
|
||||
hostlen: socklen_t,
|
||||
noalias serv: [*]u8,
|
||||
servlen: socklen_t,
|
||||
flags: u32,
|
||||
) c_int;
|
||||
|
||||
pub extern "c" fn gai_strerror(errcode: c_int) [*]const u8;
|
||||
|
||||
pub extern "c" fn poll(fds: [*]pollfd, nfds: nfds_t, timeout: c_int) c_int;
|
||||
|
||||
pub extern "c" fn dn_expand(
|
||||
msg: [*]const u8,
|
||||
eomorig: [*]const u8,
|
||||
comp_dn: [*]const u8,
|
||||
exp_dn: [*]u8,
|
||||
length: c_int,
|
||||
) c_int;
|
||||
|
@ -56,3 +56,58 @@ pub fn sigaddset(set: *sigset_t, signo: u5) void {
|
||||
}
|
||||
|
||||
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
|
||||
/// get address to use bind()
|
||||
pub const AI_PASSIVE = 0x00000001;
|
||||
|
||||
/// fill ai_canonname
|
||||
pub const AI_CANONNAME = 0x00000002;
|
||||
|
||||
/// prevent host name resolution
|
||||
pub const AI_NUMERICHOST = 0x00000004;
|
||||
|
||||
/// prevent service name resolution
|
||||
pub const AI_NUMERICSERV = 0x00001000;
|
||||
|
||||
/// address family for hostname not supported
|
||||
pub const EAI_ADDRFAMILY = 1;
|
||||
|
||||
/// temporary failure in name resolution
|
||||
pub const EAI_AGAIN = 2;
|
||||
|
||||
/// invalid value for ai_flags
|
||||
pub const EAI_BADFLAGS = 3;
|
||||
|
||||
/// non-recoverable failure in name resolution
|
||||
pub const EAI_FAIL = 4;
|
||||
|
||||
/// ai_family not supported
|
||||
pub const EAI_FAMILY = 5;
|
||||
|
||||
/// memory allocation failure
|
||||
pub const EAI_MEMORY = 6;
|
||||
|
||||
/// no address associated with hostname
|
||||
pub const EAI_NODATA = 7;
|
||||
|
||||
/// hostname nor servname provided, or not known
|
||||
pub const EAI_NONAME = 8;
|
||||
|
||||
/// servname not supported for ai_socktype
|
||||
pub const EAI_SERVICE = 9;
|
||||
|
||||
/// ai_socktype not supported
|
||||
pub const EAI_SOCKTYPE = 10;
|
||||
|
||||
/// system error returned in errno
|
||||
pub const EAI_SYSTEM = 11;
|
||||
|
||||
/// invalid value for hints
|
||||
pub const EAI_BADHINTS = 12;
|
||||
|
||||
/// resolved protocol is unknown
|
||||
pub const EAI_PROTOCOL = 13;
|
||||
|
||||
/// argument buffer overflow
|
||||
pub const EAI_OVERFLOW = 14;
|
||||
pub const EAI_MAX = 15;
|
||||
|
@ -17,6 +17,41 @@ pub const _errno = switch (builtin.abi) {
|
||||
|
||||
pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
|
||||
|
||||
pub const AI_PASSIVE = 0x01;
|
||||
pub const AI_CANONNAME = 0x02;
|
||||
pub const AI_NUMERICHOST = 0x04;
|
||||
pub const AI_V4MAPPED = 0x08;
|
||||
pub const AI_ALL = 0x10;
|
||||
pub const AI_ADDRCONFIG = 0x20;
|
||||
pub const AI_NUMERICSERV = 0x400;
|
||||
|
||||
pub const NI_NUMERICHOST = 0x01;
|
||||
pub const NI_NUMERICSERV = 0x02;
|
||||
pub const NI_NOFQDN = 0x04;
|
||||
pub const NI_NAMEREQD = 0x08;
|
||||
pub const NI_DGRAM = 0x10;
|
||||
pub const NI_NUMERICSCOPE = 0x100;
|
||||
|
||||
pub const EAI_BADFLAGS = -1;
|
||||
pub const EAI_NONAME = -2;
|
||||
pub const EAI_AGAIN = -3;
|
||||
pub const EAI_FAIL = -4;
|
||||
pub const EAI_FAMILY = -6;
|
||||
pub const EAI_SOCKTYPE = -7;
|
||||
pub const EAI_SERVICE = -8;
|
||||
pub const EAI_MEMORY = -10;
|
||||
pub const EAI_SYSTEM = -11;
|
||||
pub const EAI_OVERFLOW = -12;
|
||||
|
||||
pub const EAI_NODATA = -5;
|
||||
pub const EAI_ADDRFAMILY = -9;
|
||||
pub const EAI_INPROGRESS = -100;
|
||||
pub const EAI_CANCELED = -101;
|
||||
pub const EAI_NOTCANCELED = -102;
|
||||
pub const EAI_ALLDONE = -103;
|
||||
pub const EAI_INTR = -104;
|
||||
pub const EAI_IDN_ENCODE = -105;
|
||||
|
||||
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
|
||||
pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
|
||||
pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
|
||||
|
@ -7,7 +7,6 @@ pub const RwLock = @import("event/rwlock.zig").RwLock;
|
||||
pub const RwLocked = @import("event/rwlocked.zig").RwLocked;
|
||||
pub const Loop = @import("event/loop.zig").Loop;
|
||||
pub const fs = @import("event/fs.zig");
|
||||
pub const net = @import("event/net.zig");
|
||||
|
||||
test "import event tests" {
|
||||
_ = @import("event/channel.zig");
|
||||
@ -19,5 +18,4 @@ test "import event tests" {
|
||||
_ = @import("event/rwlock.zig");
|
||||
_ = @import("event/rwlocked.zig");
|
||||
_ = @import("event/loop.zig");
|
||||
_ = @import("event/net.zig");
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const Loop = std.event.Loop;
|
||||
|
||||
/// many producer, many consumer, thread-safe, runtime configurable buffer size
|
||||
/// when buffer is empty, consumers suspend and are resumed by producers
|
||||
/// when buffer is full, producers suspend and are resumed by consumers
|
||||
/// Many producer, many consumer, thread-safe, runtime configurable buffer size.
|
||||
/// When buffer is empty, consumers suspend and are resumed by producers.
|
||||
/// When buffer is full, producers suspend and are resumed by consumers.
|
||||
/// TODO now that async function rewrite has landed, this API should be adjusted
|
||||
/// to not use the event loop's allocator, and to not require allocation.
|
||||
pub fn Channel(comptime T: type) type {
|
||||
return struct {
|
||||
loop: *Loop,
|
||||
@ -48,7 +50,7 @@ pub fn Channel(comptime T: type) type {
|
||||
tick_node: *Loop.NextTickNode,
|
||||
};
|
||||
|
||||
/// call destroy when done
|
||||
/// Call `destroy` when done.
|
||||
pub fn create(loop: *Loop, capacity: usize) !*SelfChannel {
|
||||
const buffer_nodes = try loop.allocator.alloc(T, capacity);
|
||||
errdefer loop.allocator.free(buffer_nodes);
|
||||
|
@ -448,22 +448,67 @@ pub const Loop = struct {
|
||||
self.finishOneEvent();
|
||||
}
|
||||
|
||||
pub fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {
|
||||
defer self.linuxRemoveFd(fd);
|
||||
pub fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) void {
|
||||
assert(flags & os.EPOLLET == os.EPOLLET);
|
||||
assert(flags & os.EPOLLONESHOT == os.EPOLLONESHOT);
|
||||
var resume_node = ResumeNode.Basic{
|
||||
.base = ResumeNode{
|
||||
.id = .Basic,
|
||||
.handle = @frame(),
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
};
|
||||
var need_to_delete = false;
|
||||
defer if (need_to_delete) self.linuxRemoveFd(fd);
|
||||
|
||||
suspend {
|
||||
var resume_node = ResumeNode.Basic{
|
||||
.base = ResumeNode{
|
||||
.id = .Basic,
|
||||
.handle = @frame(),
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
if (self.linuxAddFd(fd, &resume_node.base, flags)) |_| {
|
||||
need_to_delete = true;
|
||||
} else |err| switch (err) {
|
||||
error.FileDescriptorNotRegistered => unreachable,
|
||||
error.OperationCausesCircularLoop => unreachable,
|
||||
error.FileDescriptorIncompatibleWithEpoll => unreachable,
|
||||
error.FileDescriptorAlreadyPresentInSet => unreachable, // evented writes to the same fd is not thread-safe
|
||||
|
||||
error.SystemResources,
|
||||
error.UserResourceLimitReached,
|
||||
error.Unexpected,
|
||||
=> {
|
||||
// Fall back to a blocking poll(). Ideally this codepath is never hit, since
|
||||
// epoll should be just fine. But this is better than incorrect behavior.
|
||||
var poll_flags: i16 = 0;
|
||||
if ((flags & os.EPOLLIN) != 0) poll_flags |= os.POLLIN;
|
||||
if ((flags & os.EPOLLOUT) != 0) poll_flags |= os.POLLOUT;
|
||||
var pfd = [1]os.pollfd{os.pollfd{
|
||||
.fd = fd,
|
||||
.events = poll_flags,
|
||||
.revents = undefined,
|
||||
}};
|
||||
_ = os.poll(&pfd, -1) catch |poll_err| switch (poll_err) {
|
||||
error.SystemResources,
|
||||
error.Unexpected,
|
||||
=> {
|
||||
// Even poll() didn't work. The best we can do now is sleep for a
|
||||
// small duration and then hope that something changed.
|
||||
std.time.sleep(1 * std.time.millisecond);
|
||||
},
|
||||
};
|
||||
resume @frame();
|
||||
},
|
||||
};
|
||||
try self.linuxAddFd(fd, &resume_node.base, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitUntilFdReadable(self: *Loop, fd: os.fd_t) !void {
|
||||
return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
|
||||
pub fn waitUntilFdReadable(self: *Loop, fd: os.fd_t) void {
|
||||
return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLIN);
|
||||
}
|
||||
|
||||
pub fn waitUntilFdWritable(self: *Loop, fd: os.fd_t) void {
|
||||
return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT);
|
||||
}
|
||||
|
||||
pub fn waitUntilFdWritableOrReadable(self: *Loop, fd: os.fd_t) void {
|
||||
return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN);
|
||||
}
|
||||
|
||||
pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
|
||||
@ -642,7 +687,7 @@ pub const Loop = struct {
|
||||
.linux => {
|
||||
self.posixFsRequest(&self.os_data.fs_end_request);
|
||||
// writing 8 bytes to an eventfd cannot fail
|
||||
os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
|
||||
noasync os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
|
||||
return;
|
||||
},
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => {
|
||||
@ -790,6 +835,8 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO make this whole function noasync
|
||||
// https://github.com/ziglang/zig/issues/3157
|
||||
fn posixFsRun(self: *Loop) void {
|
||||
while (true) {
|
||||
if (builtin.os == .linux) {
|
||||
@ -799,27 +846,27 @@ pub const Loop = struct {
|
||||
switch (node.data.msg) {
|
||||
.End => return,
|
||||
.WriteV => |*msg| {
|
||||
msg.result = os.writev(msg.fd, msg.iov);
|
||||
msg.result = noasync os.writev(msg.fd, msg.iov);
|
||||
},
|
||||
.PWriteV => |*msg| {
|
||||
msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
|
||||
msg.result = noasync os.pwritev(msg.fd, msg.iov, msg.offset);
|
||||
},
|
||||
.PReadV => |*msg| {
|
||||
msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
|
||||
msg.result = noasync os.preadv(msg.fd, msg.iov, msg.offset);
|
||||
},
|
||||
.Open => |*msg| {
|
||||
msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
|
||||
msg.result = noasync os.openC(msg.path.ptr, msg.flags, msg.mode);
|
||||
},
|
||||
.Close => |*msg| os.close(msg.fd),
|
||||
.Close => |*msg| noasync os.close(msg.fd),
|
||||
.WriteFile => |*msg| blk: {
|
||||
const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
|
||||
os.O_CLOEXEC | os.O_TRUNC;
|
||||
const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
|
||||
const fd = noasync os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
|
||||
msg.result = err;
|
||||
break :blk;
|
||||
};
|
||||
defer os.close(fd);
|
||||
msg.result = os.write(fd, msg.contents);
|
||||
defer noasync os.close(fd);
|
||||
msg.result = noasync os.write(fd, msg.contents);
|
||||
},
|
||||
}
|
||||
switch (node.data.finish) {
|
||||
|
@ -1,358 +0,0 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = @import("builtin");
|
||||
const testing = std.testing;
|
||||
const event = std.event;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
const Loop = std.event.Loop;
|
||||
const File = std.fs.File;
|
||||
const fd_t = os.fd_t;
|
||||
|
||||
pub const Server = struct {
|
||||
handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
|
||||
|
||||
loop: *Loop,
|
||||
sockfd: ?i32,
|
||||
accept_frame: ?anyframe,
|
||||
listen_address: std.net.Address,
|
||||
|
||||
waiting_for_emfile_node: PromiseNode,
|
||||
listen_resume_node: event.Loop.ResumeNode,
|
||||
|
||||
const PromiseNode = std.TailQueue(anyframe).Node;
|
||||
|
||||
pub fn init(loop: *Loop) Server {
|
||||
// TODO can't initialize handler here because we need well defined copy elision
|
||||
return Server{
|
||||
.loop = loop,
|
||||
.sockfd = null,
|
||||
.accept_frame = null,
|
||||
.handleRequestFn = undefined,
|
||||
.waiting_for_emfile_node = undefined,
|
||||
.listen_address = undefined,
|
||||
.listen_resume_node = event.Loop.ResumeNode{
|
||||
.id = event.Loop.ResumeNode.Id.Basic,
|
||||
.handle = undefined,
|
||||
.overlapped = event.Loop.ResumeNode.overlapped_init,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn listen(
|
||||
self: *Server,
|
||||
address: *const std.net.Address,
|
||||
handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
|
||||
) !void {
|
||||
self.handleRequestFn = handleRequestFn;
|
||||
|
||||
const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
|
||||
errdefer os.close(sockfd);
|
||||
self.sockfd = sockfd;
|
||||
|
||||
try os.bind(sockfd, &address.os_addr);
|
||||
try os.listen(sockfd, os.SOMAXCONN);
|
||||
self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
|
||||
|
||||
self.accept_frame = async Server.handler(self);
|
||||
errdefer await self.accept_frame.?;
|
||||
|
||||
self.listen_resume_node.handle = self.accept_frame.?;
|
||||
try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
|
||||
errdefer self.loop.removeFd(sockfd);
|
||||
}
|
||||
|
||||
/// Stop listening
|
||||
pub fn close(self: *Server) void {
|
||||
self.loop.linuxRemoveFd(self.sockfd.?);
|
||||
if (self.sockfd) |fd| {
|
||||
os.close(fd);
|
||||
self.sockfd = null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Server) void {
|
||||
if (self.accept_frame) |accept_frame| await accept_frame;
|
||||
if (self.sockfd) |sockfd| os.close(sockfd);
|
||||
}
|
||||
|
||||
pub async fn handler(self: *Server) void {
|
||||
while (true) {
|
||||
var accepted_addr: std.net.Address = undefined;
|
||||
// TODO just inline the following function here and don't expose it as posixAsyncAccept
|
||||
if (os.accept4_async(self.sockfd.?, &accepted_addr.os_addr, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC)) |accepted_fd| {
|
||||
if (accepted_fd == -1) {
|
||||
// would block
|
||||
suspend; // we will get resumed by epoll_wait in the event loop
|
||||
continue;
|
||||
}
|
||||
var socket = File.openHandle(accepted_fd);
|
||||
self.handleRequestFn(self, &accepted_addr, socket);
|
||||
} else |err| switch (err) {
|
||||
error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
|
||||
error.ConnectionAborted => continue,
|
||||
|
||||
error.FileDescriptorNotASocket => unreachable,
|
||||
error.OperationNotSupported => unreachable,
|
||||
|
||||
error.SystemFdQuotaExceeded, error.SystemResources, error.ProtocolFailure, error.BlockedByFirewall, error.Unexpected => {
|
||||
@panic("TODO handle this error");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
|
||||
const sockfd = try os.socket(
|
||||
os.AF_UNIX,
|
||||
os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK,
|
||||
0,
|
||||
);
|
||||
errdefer os.close(sockfd);
|
||||
|
||||
var sock_addr = os.sockaddr_un{
|
||||
.family = os.AF_UNIX,
|
||||
.path = undefined,
|
||||
};
|
||||
|
||||
if (path.len > @typeOf(sock_addr.path).len) return error.NameTooLong;
|
||||
mem.copy(u8, sock_addr.path[0..], path);
|
||||
const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
|
||||
try os.connect_async(sockfd, &sock_addr, size);
|
||||
try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
|
||||
try os.getsockoptError(sockfd);
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
pub const ReadError = error{
|
||||
SystemResources,
|
||||
Unexpected,
|
||||
UserResourceLimitReached,
|
||||
InputOutput,
|
||||
|
||||
FileDescriptorNotRegistered, // TODO remove this possibility
|
||||
OperationCausesCircularLoop, // TODO remove this possibility
|
||||
FileDescriptorAlreadyPresentInSet, // TODO remove this possibility
|
||||
FileDescriptorIncompatibleWithEpoll, // TODO remove this possibility
|
||||
};
|
||||
|
||||
/// returns number of bytes read. 0 means EOF.
|
||||
pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize {
|
||||
const iov = os.iovec{
|
||||
.iov_base = buffer.ptr,
|
||||
.iov_len = buffer.len,
|
||||
};
|
||||
const iovs: *const [1]os.iovec = &iov;
|
||||
return readvPosix(loop, fd, iovs, 1);
|
||||
}
|
||||
|
||||
pub const WriteError = error{};
|
||||
|
||||
pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteError!void {
|
||||
const iov = os.iovec_const{
|
||||
.iov_base = buffer.ptr,
|
||||
.iov_len = buffer.len,
|
||||
};
|
||||
const iovs: *const [1]os.iovec_const = &iov;
|
||||
return writevPosix(loop, fd, iovs, 1);
|
||||
}
|
||||
|
||||
pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
|
||||
while (true) {
|
||||
switch (builtin.os) {
|
||||
.macosx, .linux => {
|
||||
switch (os.errno(os.system.writev(fd, iov, count))) {
|
||||
0 => return,
|
||||
os.EINTR => continue,
|
||||
os.ESPIPE => unreachable,
|
||||
os.EINVAL => unreachable,
|
||||
os.EFAULT => unreachable,
|
||||
os.EAGAIN => {
|
||||
try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT);
|
||||
continue;
|
||||
},
|
||||
os.EBADF => unreachable, // always a race condition
|
||||
os.EDESTADDRREQ => unreachable, // connect was never called
|
||||
os.EDQUOT => unreachable,
|
||||
os.EFBIG => unreachable,
|
||||
os.EIO => return error.InputOutput,
|
||||
os.ENOSPC => unreachable,
|
||||
os.EPERM => return error.AccessDenied,
|
||||
os.EPIPE => unreachable,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// returns number of bytes read. 0 means EOF.
|
||||
pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count: usize) !usize {
|
||||
while (true) {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.macosx => {
|
||||
const rc = os.system.readv(fd, iov, count);
|
||||
switch (os.errno(rc)) {
|
||||
0 => return rc,
|
||||
os.EINTR => continue,
|
||||
os.EINVAL => unreachable,
|
||||
os.EFAULT => unreachable,
|
||||
os.EAGAIN => {
|
||||
try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
|
||||
continue;
|
||||
},
|
||||
os.EBADF => unreachable, // always a race condition
|
||||
os.EIO => return error.InputOutput,
|
||||
os.EISDIR => unreachable,
|
||||
os.ENOBUFS => return error.SystemResources,
|
||||
os.ENOMEM => return error.SystemResources,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
|
||||
const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
|
||||
defer loop.allocator.free(iovecs);
|
||||
|
||||
for (data) |buf, i| {
|
||||
iovecs[i] = os.iovec_const{
|
||||
.iov_base = buf.ptr,
|
||||
.iov_len = buf.len,
|
||||
};
|
||||
}
|
||||
|
||||
return writevPosix(loop, fd, iovecs.ptr, data.len);
|
||||
}
|
||||
|
||||
pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
|
||||
const iovecs = try loop.allocator.alloc(os.iovec, data.len);
|
||||
defer loop.allocator.free(iovecs);
|
||||
|
||||
for (data) |buf, i| {
|
||||
iovecs[i] = os.iovec{
|
||||
.iov_base = buf.ptr,
|
||||
.iov_len = buf.len,
|
||||
};
|
||||
}
|
||||
|
||||
return readvPosix(loop, fd, iovecs.ptr, data.len);
|
||||
}
|
||||
|
||||
pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
|
||||
var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592
|
||||
|
||||
const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
|
||||
errdefer os.close(sockfd);
|
||||
|
||||
try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
|
||||
try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
|
||||
try os.getsockoptError(sockfd);
|
||||
|
||||
return File.openHandle(sockfd);
|
||||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
// https://github.com/ziglang/zig/issues/2377
|
||||
if (true) return error.SkipZigTest;
|
||||
|
||||
if (builtin.os != builtin.Os.linux) {
|
||||
// TODO build abstractions for other operating systems
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
const MyServer = struct {
|
||||
tcp_server: Server,
|
||||
|
||||
const Self = @This();
|
||||
async fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
|
||||
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
|
||||
var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
|
||||
defer socket.close();
|
||||
const next_handler = errorableHandler(self, _addr, socket) catch |err| {
|
||||
std.debug.panic("unable to handle connection: {}\n", err);
|
||||
};
|
||||
}
|
||||
async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
|
||||
const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
|
||||
var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
|
||||
|
||||
const stream = &socket.outStream().stream;
|
||||
try stream.print("hello from server\n");
|
||||
}
|
||||
};
|
||||
|
||||
const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
|
||||
const addr = std.net.Address.initIp4(ip4addr, 0);
|
||||
|
||||
var loop: Loop = undefined;
|
||||
try loop.initSingleThreaded(std.debug.global_allocator);
|
||||
var server = MyServer{ .tcp_server = Server.init(&loop) };
|
||||
defer server.tcp_server.deinit();
|
||||
try server.tcp_server.listen(&addr, MyServer.handler);
|
||||
|
||||
_ = async doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
|
||||
loop.run();
|
||||
}
|
||||
|
||||
async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
|
||||
errdefer @panic("test failure");
|
||||
|
||||
var socket_file = try connect(loop, address);
|
||||
defer socket_file.close();
|
||||
|
||||
var buf: [512]u8 = undefined;
|
||||
const amt_read = try socket_file.read(buf[0..]);
|
||||
const msg = buf[0..amt_read];
|
||||
testing.expect(mem.eql(u8, msg, "hello from server\n"));
|
||||
server.close();
|
||||
}
|
||||
|
||||
pub const OutStream = struct {
|
||||
fd: fd_t,
|
||||
stream: Stream,
|
||||
loop: *Loop,
|
||||
|
||||
pub const Error = WriteError;
|
||||
pub const Stream = event.io.OutStream(Error);
|
||||
|
||||
pub fn init(loop: *Loop, fd: fd_t) OutStream {
|
||||
return OutStream{
|
||||
.fd = fd,
|
||||
.loop = loop,
|
||||
.stream = Stream{ .writeFn = writeFn },
|
||||
};
|
||||
}
|
||||
|
||||
async fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
|
||||
const self = @fieldParentPtr(OutStream, "stream", out_stream);
|
||||
return write(self.loop, self.fd, bytes);
|
||||
}
|
||||
};
|
||||
|
||||
pub const InStream = struct {
|
||||
fd: fd_t,
|
||||
stream: Stream,
|
||||
loop: *Loop,
|
||||
|
||||
pub const Error = ReadError;
|
||||
pub const Stream = event.io.InStream(Error);
|
||||
|
||||
pub fn init(loop: *Loop, fd: fd_t) InStream {
|
||||
return InStream{
|
||||
.fd = fd,
|
||||
.loop = loop,
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
}
|
||||
|
||||
async fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
|
||||
const self = @fieldParentPtr(InStream, "stream", in_stream);
|
||||
return read(self.loop, self.fd, bytes);
|
||||
}
|
||||
};
|
@ -53,7 +53,7 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
|
||||
/// The format string must be comptime known and may contain placeholders following
|
||||
/// this format:
|
||||
/// `{[position][specifier]:[fill][alignment][width].[precision]}`
|
||||
///
|
||||
///
|
||||
/// Each word between `[` and `]` is a parameter you have to replace with something:
|
||||
///
|
||||
/// - *position* is the index of the argument that should be inserted
|
||||
@ -78,7 +78,7 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
|
||||
/// - `d`: output numeric value in decimal notation
|
||||
/// - `b`: output integer value in binary notation
|
||||
/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
|
||||
/// - `*`: output the address of the value instead of the value itself.
|
||||
/// - `*`: output the address of the value instead of the value itself.
|
||||
///
|
||||
/// If a formatted user type contains a function of the type
|
||||
/// ```
|
||||
|
@ -704,7 +704,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Call `File.close` on the result when done.
|
||||
pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File {
|
||||
const flags = os.O_LARGEFILE | os.O_RDONLY;
|
||||
const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
|
||||
const fd = try os.openatC(self.fd, sub_path, flags, 0);
|
||||
return File.openHandle(fd);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ pub const File = struct {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||
return openReadW(&path_w);
|
||||
}
|
||||
const flags = os.O_LARGEFILE | os.O_RDONLY;
|
||||
const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
|
||||
const fd = try os.openC(path, flags, 0);
|
||||
return openHandle(fd);
|
||||
}
|
||||
|
@ -64,68 +64,7 @@ pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
|
||||
pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream;
|
||||
pub const COutStream = @import("io/c_out_stream.zig").COutStream;
|
||||
pub const InStream = @import("io/in_stream.zig").InStream;
|
||||
|
||||
pub fn OutStream(comptime WriteError: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
pub const Error = WriteError;
|
||||
|
||||
writeFn: fn (self: *Self, bytes: []const u8) Error!void,
|
||||
|
||||
pub fn print(self: *Self, comptime format: []const u8, args: ...) Error!void {
|
||||
return std.fmt.format(self, Error, self.writeFn, format, args);
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!void {
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeByte(self: *Self, byte: u8) Error!void {
|
||||
const slice = (*const [1]u8)(&byte)[0..];
|
||||
return self.writeFn(self, slice);
|
||||
}
|
||||
|
||||
pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) Error!void {
|
||||
const slice = (*const [1]u8)(&byte)[0..];
|
||||
var i: usize = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
try self.writeFn(self, slice);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a native-endian integer.
|
||||
pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntNative(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
/// Write a foreign-endian integer.
|
||||
pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntForeign(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntLittle(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntBig(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeInt(T, &bytes, value, endian);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
};
|
||||
}
|
||||
pub const OutStream = @import("io/out_stream.zig").OutStream;
|
||||
|
||||
/// TODO move this to `std.fs` and add a version to `std.fs.Dir`.
|
||||
pub fn writeFile(path: []const u8, data: []const u8) !void {
|
||||
|
@ -11,7 +11,6 @@ pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream"))
|
||||
root.stack_size_std_io_InStream
|
||||
else
|
||||
default_stack_size;
|
||||
pub const stack_align = 16;
|
||||
|
||||
pub fn InStream(comptime ReadError: type) type {
|
||||
return struct {
|
||||
@ -34,7 +33,7 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
if (std.io.is_async) {
|
||||
// Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream read.
|
||||
@setRuntimeSafety(false);
|
||||
var stack_frame: [stack_size]u8 align(stack_align) = undefined;
|
||||
var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
|
||||
return await @asyncCall(&stack_frame, {}, self.readFn, self, buffer);
|
||||
} else {
|
||||
return self.readFn(self, buffer);
|
||||
@ -130,6 +129,47 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
/// Reads from the stream until specified byte is found. If the buffer is not
|
||||
/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
|
||||
/// If end-of-stream is found, returns the rest of the stream. If this
|
||||
/// function is called again after that, returns null.
|
||||
/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
|
||||
/// delimiter byte is not included in the returned slice.
|
||||
pub fn readUntilDelimiterOrEof(self: *Self, buf: []u8, delimiter: u8) !?[]u8 {
|
||||
var index: usize = 0;
|
||||
while (true) {
|
||||
const byte = self.readByte() catch |err| switch (err) {
|
||||
error.EndOfStream => {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return buf[0..index];
|
||||
}
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
if (byte == delimiter) return buf[0..index];
|
||||
if (index >= buf.len) return error.StreamTooLong;
|
||||
|
||||
buf[index] = byte;
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads from the stream until specified byte is found, discarding all data,
|
||||
/// including the delimiter.
|
||||
/// If end-of-stream is found, this function succeeds.
|
||||
pub fn skipUntilDelimiterOrEof(self: *Self, delimiter: u8) !void {
|
||||
while (true) {
|
||||
const byte = self.readByte() catch |err| switch (err) {
|
||||
error.EndOfStream => return,
|
||||
else => |e| return e,
|
||||
};
|
||||
if (byte == delimiter) return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads 1 byte from the stream or returns `error.EndOfStream`.
|
||||
pub fn readByte(self: *Self) !u8 {
|
||||
var result: [1]u8 = undefined;
|
||||
|
87
lib/std/io/out_stream.zig
Normal file
87
lib/std/io/out_stream.zig
Normal file
@ -0,0 +1,87 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = @import("builtin");
|
||||
const root = @import("root");
|
||||
const mem = std.mem;
|
||||
|
||||
pub const default_stack_size = 1 * 1024 * 1024;
|
||||
pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_OutStream"))
|
||||
root.stack_size_std_io_OutStream
|
||||
else
|
||||
default_stack_size;
|
||||
|
||||
/// TODO this is not integrated with evented I/O yet.
|
||||
/// https://github.com/ziglang/zig/issues/3557
|
||||
pub fn OutStream(comptime WriteError: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
pub const Error = WriteError;
|
||||
// TODO https://github.com/ziglang/zig/issues/3557
|
||||
pub const WriteFn = if (std.io.is_async and false)
|
||||
async fn (self: *Self, bytes: []const u8) Error!void
|
||||
else
|
||||
fn (self: *Self, bytes: []const u8) Error!void;
|
||||
|
||||
writeFn: WriteFn,
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!void {
|
||||
// TODO https://github.com/ziglang/zig/issues/3557
|
||||
if (std.io.is_async and false) {
|
||||
// Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream write.
|
||||
@setRuntimeSafety(false);
|
||||
var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
|
||||
return await @asyncCall(&stack_frame, {}, self.writeFn, self, bytes);
|
||||
} else {
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(self: *Self, comptime format: []const u8, args: ...) Error!void {
|
||||
return std.fmt.format(self, Error, self.writeFn, format, args);
|
||||
}
|
||||
|
||||
pub fn writeByte(self: *Self, byte: u8) Error!void {
|
||||
const slice = (*const [1]u8)(&byte)[0..];
|
||||
return self.writeFn(self, slice);
|
||||
}
|
||||
|
||||
pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) Error!void {
|
||||
const slice = (*const [1]u8)(&byte)[0..];
|
||||
var i: usize = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
try self.writeFn(self, slice);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a native-endian integer.
|
||||
pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntNative(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
/// Write a foreign-endian integer.
|
||||
pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntForeign(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntLittle(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntBig(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeInt(T, &bytes, value, endian);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
};
|
||||
}
|
@ -99,7 +99,7 @@ pub const Allocator = struct {
|
||||
/// memory is no longer needed, to avoid a resource leak. If the
|
||||
/// `Allocator` implementation is unknown, then correct code will
|
||||
/// call `free` when done.
|
||||
///
|
||||
///
|
||||
/// For allocating a single item, see `create`.
|
||||
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
|
||||
return self.alignedAlloc(T, null, n);
|
||||
|
1497
lib/std/net.zig
1497
lib/std/net.zig
File diff suppressed because it is too large
Load Diff
91
lib/std/net/test.zig
Normal file
91
lib/std/net/test.zig
Normal file
@ -0,0 +1,91 @@
|
||||
const std = @import("../std.zig");
|
||||
const net = std.net;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
test "parse and render IPv6 addresses" {
|
||||
const addr = try net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
|
||||
var buf: [100]u8 = undefined;
|
||||
const printed = try std.fmt.bufPrint(&buf, "{}", addr);
|
||||
std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
|
||||
}
|
||||
|
||||
test "parse and render IPv4 addresses" {
|
||||
var buffer: [18]u8 = undefined;
|
||||
for ([_][]const u8{
|
||||
"0.0.0.0",
|
||||
"255.255.255.255",
|
||||
"1.2.3.4",
|
||||
"123.255.0.91",
|
||||
"127.0.0.1",
|
||||
}) |ip| {
|
||||
var addr = net.IpAddress.parseIp4(ip, 0);
|
||||
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
|
||||
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
|
||||
}
|
||||
|
||||
testing.expectError(error.Overflow, net.IpAddress.parseIp4("256.0.0.1", 0));
|
||||
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("x.0.0.1", 0));
|
||||
testing.expectError(error.InvalidEnd, net.IpAddress.parseIp4("127.0.0.1.1", 0));
|
||||
testing.expectError(error.Incomplete, net.IpAddress.parseIp4("127.0.0.", 0));
|
||||
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("100..0.1", 0));
|
||||
}
|
||||
|
||||
test "resolve DNS" {
|
||||
if (std.builtin.os == .windows) {
|
||||
// DNS resolution not implemented on Windows yet.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
var buf: [1000 * 10]u8 = undefined;
|
||||
const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
|
||||
|
||||
const address_list = net.getAddressList(a, "example.com", 80) catch |err| switch (err) {
|
||||
// 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,
|
||||
};
|
||||
address_list.deinit();
|
||||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
if (std.builtin.os != .linux) {
|
||||
// TODO build abstractions for other operating systems
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (std.io.mode != .evented) {
|
||||
// TODO add ability to run tests in non-blocking I/O mode
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
// TODO doing this at comptime crashed the compiler
|
||||
const localhost = net.IpAddress.parse("127.0.0.1", 0);
|
||||
|
||||
var server = net.TcpServer.init(net.TcpServer.Options{});
|
||||
defer server.deinit();
|
||||
try server.listen(localhost);
|
||||
|
||||
var server_frame = async testServer(&server);
|
||||
var client_frame = async testClient(server.listen_address);
|
||||
|
||||
try await server_frame;
|
||||
try await client_frame;
|
||||
}
|
||||
|
||||
fn testClient(addr: net.IpAddress) anyerror!void {
|
||||
const socket_file = try net.tcpConnectToAddress(addr);
|
||||
defer socket_file.close();
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
const len = try socket_file.read(&buf);
|
||||
const msg = buf[0..len];
|
||||
testing.expect(mem.eql(u8, msg, "hello from server\n"));
|
||||
}
|
||||
|
||||
fn testServer(server: *net.TcpServer) anyerror!void {
|
||||
var client_file = try server.accept();
|
||||
|
||||
const stream = &client_file.outStream().stream;
|
||||
try stream.print("hello from server\n");
|
||||
}
|
474
lib/std/os.zig
474
lib/std/os.zig
@ -310,7 +310,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd) catch return error.WouldBlock;
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
@ -327,7 +327,36 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
}
|
||||
|
||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
||||
/// This function is for blocking file descriptors only.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
||||
while (true) {
|
||||
// TODO handle the case when iov_len is too large and get rid of this @intCast
|
||||
const rc = system.readv(fd, iov.ptr, @intCast(u32, iov.len));
|
||||
switch (errno(rc)) {
|
||||
0 => return @bitCast(usize, rc),
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // always a race condition
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
|
||||
if (comptime std.Target.current.isDarwin()) {
|
||||
// Darwin does not have preadv but it does have pread.
|
||||
@ -357,7 +386,12 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
ESPIPE => unreachable, // fd is not seekable
|
||||
EAGAIN => unreachable, // This function is for blocking reads.
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // always a race condition
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -375,7 +409,12 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => unreachable, // This function is for blocking reads.
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // always a race condition
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -395,10 +434,17 @@ pub const WriteError = error{
|
||||
BrokenPipe,
|
||||
SystemResources,
|
||||
OperationAborted,
|
||||
|
||||
/// This error occurs when no global event loop is configured,
|
||||
/// and reading from the file descriptor would block.
|
||||
WouldBlock,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Write to a file descriptor. Keeps trying if it gets interrupted.
|
||||
/// This function is for blocking file descriptors only.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
/// TODO evented I/O integration is disabled until
|
||||
/// https://github.com/ziglang/zig/issues/3557 is solved.
|
||||
pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
|
||||
if (builtin.os == .windows) {
|
||||
return windows.WriteFile(fd, bytes);
|
||||
@ -434,7 +480,14 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => unreachable, // This function is for blocking writes.
|
||||
// TODO https://github.com/ziglang/zig/issues/3557
|
||||
EAGAIN => return error.WouldBlock,
|
||||
//EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
// loop.waitUntilFdWritable(fd);
|
||||
// continue;
|
||||
//} else {
|
||||
// return error.WouldBlock;
|
||||
//},
|
||||
EBADF => unreachable, // Always a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -448,9 +501,9 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted.
|
||||
/// This function is for blocking file descriptors only. For non-blocking, see
|
||||
/// `writevAsync`.
|
||||
/// Write multiple buffers to a file descriptor.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
|
||||
while (true) {
|
||||
// TODO handle the case when iov_len is too large and get rid of this @intCast
|
||||
@ -460,7 +513,12 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => unreachable, // This function is for blocking writes.
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // Always a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -476,8 +534,6 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
|
||||
|
||||
/// Write multiple buffers to a file descriptor, with a position offset.
|
||||
/// Keeps trying if it gets interrupted.
|
||||
/// This function is for blocking file descriptors only. For non-blocking, see
|
||||
/// `pwritevAsync`.
|
||||
pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void {
|
||||
if (comptime std.Target.current.isDarwin()) {
|
||||
// Darwin does not have pwritev but it does have pwrite.
|
||||
@ -506,7 +562,12 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void
|
||||
ESPIPE => unreachable, // `fd` is not seekable.
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => unreachable, // This function is for blocking writes.
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // Always a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -528,7 +589,12 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => unreachable, // This function is for blocking writes.
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EBADF => unreachable, // Always a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -1510,16 +1576,17 @@ pub const SocketError = error{
|
||||
ProtocolNotSupported,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 {
|
||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
|
||||
const rc = system.socket(domain, socket_type, protocol);
|
||||
switch (errno(rc)) {
|
||||
0 => return @intCast(i32, rc),
|
||||
0 => return @intCast(fd_t, rc),
|
||||
EACCES => return error.PermissionDenied,
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
EINVAL => return error.ProtocolFamilyNotAvailable,
|
||||
EMFILE => return error.ProcessFdQuotaExceeded,
|
||||
ENFILE => return error.SystemFdQuotaExceeded,
|
||||
ENOBUFS, ENOMEM => return error.SystemResources,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
EPROTONOSUPPORT => return error.ProtocolNotSupported,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
@ -1561,17 +1628,17 @@ pub const BindError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
/// addr is `*const T` where T is one of the sockaddr
|
||||
pub fn bind(fd: i32, addr: *const sockaddr) BindError!void {
|
||||
const rc = system.bind(fd, addr, @sizeOf(sockaddr));
|
||||
pub fn bind(sockfd: fd_t, addr: *const sockaddr, len: socklen_t) BindError!void {
|
||||
const rc = system.bind(sockfd, addr, len);
|
||||
switch (errno(rc)) {
|
||||
0 => return,
|
||||
EACCES => return error.AccessDenied,
|
||||
EADDRINUSE => return error.AddressInUse,
|
||||
EBADF => unreachable, // always a race condition if this error is returned
|
||||
EINVAL => unreachable,
|
||||
ENOTSOCK => unreachable,
|
||||
EINVAL => unreachable, // invalid parameters
|
||||
ENOTSOCK => unreachable, // invalid `sockfd`
|
||||
EADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
EFAULT => unreachable,
|
||||
EFAULT => unreachable, // invalid `addr` pointer
|
||||
ELOOP => return error.SymLinkLoop,
|
||||
ENAMETOOLONG => return error.NameTooLong,
|
||||
ENOENT => return error.FileNotFound,
|
||||
@ -1622,12 +1689,6 @@ pub const AcceptError = error{
|
||||
/// by the socket buffer limits, not by the system memory.
|
||||
SystemResources,
|
||||
|
||||
/// The file descriptor sockfd does not refer to a socket.
|
||||
FileDescriptorNotASocket,
|
||||
|
||||
/// The referenced socket is not of type SOCK_STREAM.
|
||||
OperationNotSupported,
|
||||
|
||||
ProtocolFailure,
|
||||
|
||||
/// Firewall rules forbid connection.
|
||||
@ -1644,7 +1705,7 @@ pub const AcceptError = error{
|
||||
pub fn accept4(
|
||||
/// This argument is a socket that has been created with `socket`, bound to a local address
|
||||
/// with `bind`, and is listening for connections after a `listen`.
|
||||
sockfd: i32,
|
||||
sockfd: fd_t,
|
||||
/// This argument is a pointer to a sockaddr structure. This structure is filled in with the
|
||||
/// address of the peer socket, as known to the communications layer. The exact format of the
|
||||
/// address returned addr is determined by the socket's address family (see `socket` and the
|
||||
@ -1665,15 +1726,15 @@ pub fn accept4(
|
||||
/// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
|
||||
/// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
|
||||
flags: u32,
|
||||
) AcceptError!i32 {
|
||||
) AcceptError!fd_t {
|
||||
while (true) {
|
||||
const rc = system.accept4(sockfd, addr, addr_size, flags);
|
||||
switch (errno(rc)) {
|
||||
0 => return @intCast(i32, rc),
|
||||
0 => return @intCast(fd_t, rc),
|
||||
EINTR => continue,
|
||||
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(sockfd) catch return error.WouldBlock;
|
||||
loop.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
@ -1682,12 +1743,12 @@ pub fn accept4(
|
||||
ECONNABORTED => return error.ConnectionAborted,
|
||||
EFAULT => unreachable,
|
||||
EINVAL => unreachable,
|
||||
ENOTSOCK => unreachable,
|
||||
EMFILE => return error.ProcessFdQuotaExceeded,
|
||||
ENFILE => return error.SystemFdQuotaExceeded,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOTSOCK => return error.FileDescriptorNotASocket,
|
||||
EOPNOTSUPP => return error.OperationNotSupported,
|
||||
EOPNOTSUPP => unreachable,
|
||||
EPROTO => return error.ProtocolFailure,
|
||||
EPERM => return error.BlockedByFirewall,
|
||||
|
||||
@ -1809,11 +1870,9 @@ pub const GetSockNameError = error{
|
||||
SystemResources,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr {
|
||||
var addr: sockaddr = undefined;
|
||||
var addrlen: socklen_t = @sizeOf(sockaddr);
|
||||
switch (errno(system.getsockname(sockfd, &addr, &addrlen))) {
|
||||
0 => return addr,
|
||||
pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
|
||||
switch (errno(system.getsockname(sockfd, addr, addrlen))) {
|
||||
0 => return,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
|
||||
EBADF => unreachable, // always a race condition
|
||||
@ -1856,12 +1915,14 @@ pub const ConnectError = error{
|
||||
/// 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.
|
||||
ConnectionTimedOut,
|
||||
|
||||
/// This error occurs when no global event loop is configured,
|
||||
/// and connecting to the socket would block.
|
||||
WouldBlock,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Initiate a connection on a socket.
|
||||
/// This is for blocking file descriptors only.
|
||||
/// For non-blocking, see `connect_async`.
|
||||
pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
|
||||
pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
|
||||
while (true) {
|
||||
switch (errno(system.connect(sockfd, sock_addr, len))) {
|
||||
0 => return,
|
||||
@ -1870,12 +1931,15 @@ pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!v
|
||||
EADDRINUSE => return error.AddressInUse,
|
||||
EADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
EAGAIN => return error.SystemResources,
|
||||
EAGAIN, EINPROGRESS => {
|
||||
const loop = std.event.Loop.instance orelse return error.WouldBlock;
|
||||
loop.waitUntilFdWritableOrReadable(sockfd);
|
||||
return getsockoptError(sockfd);
|
||||
},
|
||||
EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
|
||||
EBADF => unreachable, // sockfd is not a valid open file descriptor.
|
||||
ECONNREFUSED => return error.ConnectionRefused,
|
||||
EFAULT => unreachable, // The socket structure address is outside the user's address space.
|
||||
EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
|
||||
EINTR => continue,
|
||||
EISCONN => unreachable, // The socket is already connected.
|
||||
ENETUNREACH => return error.NetworkUnreachable,
|
||||
@ -1887,34 +1951,6 @@ pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!v
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `connect` except it is for non-blocking socket file descriptors.
|
||||
/// It expects to receive EINPROGRESS`.
|
||||
pub fn connect_async(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
|
||||
while (true) {
|
||||
switch (errno(system.connect(sockfd, sock_addr, len))) {
|
||||
EINVAL => unreachable,
|
||||
EINTR => continue,
|
||||
0, EINPROGRESS => return,
|
||||
EACCES => return error.PermissionDenied,
|
||||
EPERM => return error.PermissionDenied,
|
||||
EADDRINUSE => return error.AddressInUse,
|
||||
EADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
EAGAIN => return error.SystemResources,
|
||||
EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
|
||||
EBADF => unreachable, // sockfd is not a valid open file descriptor.
|
||||
ECONNREFUSED => return error.ConnectionRefused,
|
||||
EFAULT => unreachable, // The socket structure address is outside the user's address space.
|
||||
EISCONN => unreachable, // The socket is already connected.
|
||||
ENETUNREACH => return error.NetworkUnreachable,
|
||||
ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
|
||||
EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
|
||||
ETIMEDOUT => return error.ConnectionTimedOut,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getsockoptError(sockfd: i32) ConnectError!void {
|
||||
var err_code: u32 = undefined;
|
||||
var size: u32 = @sizeOf(u32);
|
||||
@ -2835,3 +2871,297 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
|
||||
|
||||
@compileError("TODO implement gethostname for this OS");
|
||||
}
|
||||
|
||||
pub fn res_mkquery(
|
||||
op: u4,
|
||||
dname: []const u8,
|
||||
class: u8,
|
||||
ty: u8,
|
||||
data: []const u8,
|
||||
newrr: ?[*]const u8,
|
||||
buf: []u8,
|
||||
) usize {
|
||||
// This implementation is ported from musl libc.
|
||||
// A more idiomatic "ziggy" implementation would be welcome.
|
||||
var name = dname;
|
||||
if (mem.endsWith(u8, name, ".")) name.len -= 1;
|
||||
assert(name.len <= 253);
|
||||
const n = 17 + name.len + @boolToInt(name.len != 0);
|
||||
|
||||
// Construct query template - ID will be filled later
|
||||
var q: [280]u8 = undefined;
|
||||
@memset(&q, 0, n);
|
||||
q[2] = u8(op) * 8 + 1;
|
||||
q[5] = 1;
|
||||
mem.copy(u8, q[13..], name);
|
||||
var i: usize = 13;
|
||||
var j: usize = undefined;
|
||||
while (q[i] != 0) : (i = j + 1) {
|
||||
j = i;
|
||||
while (q[j] != 0 and q[j] != '.') : (j += 1) {}
|
||||
// TODO determine the circumstances for this and whether or
|
||||
// not this should be an error.
|
||||
if (j - i - 1 > 62) unreachable;
|
||||
q[i - 1] = @intCast(u8, j - i);
|
||||
}
|
||||
q[i + 1] = ty;
|
||||
q[i + 3] = class;
|
||||
|
||||
// Make a reasonably unpredictable id
|
||||
var ts: timespec = undefined;
|
||||
clock_gettime(CLOCK_REALTIME, &ts) catch {};
|
||||
const UInt = @IntType(false, @typeOf(ts.tv_nsec).bit_count);
|
||||
const unsec = @bitCast(UInt, ts.tv_nsec);
|
||||
const id = @truncate(u32, unsec + unsec / 65536);
|
||||
q[0] = @truncate(u8, id / 256);
|
||||
q[1] = @truncate(u8, id);
|
||||
|
||||
mem.copy(u8, buf, q[0..n]);
|
||||
return n;
|
||||
}
|
||||
|
||||
pub const SendError = error{
|
||||
/// (For UNIX domain sockets, which are identified by pathname) Write permission is denied
|
||||
/// on the destination socket file, or search permission is denied for one of the
|
||||
/// directories the path prefix. (See path_resolution(7).)
|
||||
/// (For UDP sockets) An attempt was made to send to a network/broadcast address as though
|
||||
/// it was a unicast address.
|
||||
AccessDenied,
|
||||
|
||||
/// The socket is marked nonblocking and the requested operation would block, and
|
||||
/// there is no global event loop configured.
|
||||
/// It's also possible to get this error under the following condition:
|
||||
/// (Internet domain datagram 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).
|
||||
WouldBlock,
|
||||
|
||||
/// Another Fast Open is already in progress.
|
||||
FastOpenAlreadyInProgress,
|
||||
|
||||
/// Connection reset by peer.
|
||||
ConnectionResetByPeer,
|
||||
|
||||
/// The socket type requires that message be sent atomically, and the size of the message
|
||||
/// to be sent made this impossible. The message is not transmitted.
|
||||
///
|
||||
MessageTooBig,
|
||||
|
||||
/// The output queue for a network interface was full. This generally indicates that the
|
||||
/// interface has stopped sending, but may be caused by transient congestion. (Normally,
|
||||
/// this does not occur in Linux. Packets are just silently dropped when a device queue
|
||||
/// overflows.)
|
||||
/// This is also caused when there is not enough kernel memory available.
|
||||
SystemResources,
|
||||
|
||||
/// The local end has been shut down on a connection oriented socket. In this case, the
|
||||
/// process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
|
||||
BrokenPipe,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Transmit a message to another socket.
|
||||
///
|
||||
/// The `sendto` call may be used only when the socket is in a connected state (so that the intended
|
||||
/// recipient is known). The following call
|
||||
///
|
||||
/// send(sockfd, buf, len, flags);
|
||||
///
|
||||
/// is equivalent to
|
||||
///
|
||||
/// sendto(sockfd, buf, len, flags, NULL, 0);
|
||||
///
|
||||
/// If sendto() is used on a connection-mode (`SOCK_STREAM`, `SOCK_SEQPACKET`) socket, the arguments
|
||||
/// `dest_addr` and `addrlen` are asserted to be `null` and `0` respectively, and asserted
|
||||
/// that the socket was actually connected.
|
||||
/// Otherwise, the address of the target is given by `dest_addr` with `addrlen` specifying its size.
|
||||
///
|
||||
/// If the message is too long to pass atomically through the underlying protocol,
|
||||
/// `SendError.MessageTooBig` is returned, and the message is not transmitted.
|
||||
///
|
||||
/// There is no indication of failure to deliver.
|
||||
///
|
||||
/// When the message does not fit into the send buffer of the socket, `sendto` normally blocks,
|
||||
/// unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail
|
||||
/// with `SendError.WouldBlock`. The `select` call may be used to determine when it is
|
||||
/// possible to send more data.
|
||||
pub fn sendto(
|
||||
/// The file descriptor of the sending socket.
|
||||
sockfd: fd_t,
|
||||
/// Message to send.
|
||||
buf: []const u8,
|
||||
flags: u32,
|
||||
dest_addr: ?*const sockaddr,
|
||||
addrlen: socklen_t,
|
||||
) SendError!usize {
|
||||
while (true) {
|
||||
const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
|
||||
switch (errno(rc)) {
|
||||
0 => return rc,
|
||||
|
||||
EACCES => return error.AccessDenied,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EALREADY => return error.FastOpenAlreadyInProgress,
|
||||
EBADF => unreachable, // always a race condition
|
||||
ECONNRESET => return error.ConnectionResetByPeer,
|
||||
EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
|
||||
EFAULT => unreachable, // An invalid user space address was specified for an argument.
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable, // Invalid argument passed.
|
||||
EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
|
||||
EMSGSIZE => return error.MessageTooBig,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOTCONN => unreachable, // The socket is not connected, and no target has been given.
|
||||
ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
|
||||
EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
|
||||
EPIPE => return error.BrokenPipe,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transmit a message to another socket.
|
||||
///
|
||||
/// The `send` call may be used only when the socket is in a connected state (so that the intended
|
||||
/// recipient is known). The only difference between `send` and `write` is the presence of
|
||||
/// flags. With a zero flags argument, `send` is equivalent to `write`. Also, the following
|
||||
/// call
|
||||
///
|
||||
/// send(sockfd, buf, len, flags);
|
||||
///
|
||||
/// is equivalent to
|
||||
///
|
||||
/// sendto(sockfd, buf, len, flags, NULL, 0);
|
||||
///
|
||||
/// There is no indication of failure to deliver.
|
||||
///
|
||||
/// When the message does not fit into the send buffer of the socket, `send` normally blocks,
|
||||
/// unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail
|
||||
/// with `SendError.WouldBlock`. The `select` call may be used to determine when it is
|
||||
/// possible to send more data.
|
||||
pub fn send(
|
||||
/// The file descriptor of the sending socket.
|
||||
sockfd: fd_t,
|
||||
buf: []const u8,
|
||||
flags: u32,
|
||||
) SendError!usize {
|
||||
return sendto(sockfd, buf, flags, null, 0);
|
||||
}
|
||||
|
||||
pub const PollError = error{
|
||||
/// The kernel had no space to allocate file descriptor tables.
|
||||
SystemResources,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {
|
||||
while (true) {
|
||||
const rc = system.poll(fds.ptr, fds.len, timeout);
|
||||
switch (errno(rc)) {
|
||||
0 => return rc,
|
||||
EFAULT => unreachable,
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
ENOMEM => return error.SystemResources,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const RecvFromError = error{
|
||||
/// The socket is marked nonblocking and the requested operation would block, and
|
||||
/// there is no global event loop configured.
|
||||
WouldBlock,
|
||||
|
||||
/// A remote host refused to allow the network connection, typically because it is not
|
||||
/// running the requested service.
|
||||
ConnectionRefused,
|
||||
|
||||
/// Could not allocate kernel memory.
|
||||
SystemResources,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn recvfrom(
|
||||
sockfd: fd_t,
|
||||
buf: []u8,
|
||||
flags: u32,
|
||||
src_addr: ?*sockaddr,
|
||||
addrlen: ?*socklen_t,
|
||||
) RecvFromError!usize {
|
||||
while (true) {
|
||||
const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);
|
||||
switch (errno(rc)) {
|
||||
0 => return rc,
|
||||
EBADF => unreachable, // always a race condition
|
||||
EFAULT => unreachable,
|
||||
EINVAL => unreachable,
|
||||
ENOTCONN => unreachable,
|
||||
ENOTSOCK => unreachable,
|
||||
EINTR => continue,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
ENOMEM => return error.SystemResources,
|
||||
ECONNREFUSED => return error.ConnectionRefused,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const DnExpandError = error{InvalidDnsPacket};
|
||||
|
||||
pub fn dn_expand(
|
||||
msg: []const u8,
|
||||
comp_dn: []const u8,
|
||||
exp_dn: []u8,
|
||||
) DnExpandError!usize {
|
||||
// This implementation is ported from musl libc.
|
||||
// A more idiomatic "ziggy" implementation would be welcome.
|
||||
var p = comp_dn.ptr;
|
||||
var len: usize = std.math.maxInt(usize);
|
||||
const end = msg.ptr + msg.len;
|
||||
if (p == end or exp_dn.len == 0) return error.InvalidDnsPacket;
|
||||
var dest = exp_dn.ptr;
|
||||
const dend = dest + std.math.min(exp_dn.len, 254);
|
||||
// detect reference loop using an iteration counter
|
||||
var i: usize = 0;
|
||||
while (i < msg.len) : (i += 2) {
|
||||
// loop invariants: p<end, dest<dend
|
||||
if ((p[0] & 0xc0) != 0) {
|
||||
if (p + 1 == end) return error.InvalidDnsPacket;
|
||||
var j = ((p[0] & usize(0x3f)) << 8) | p[1];
|
||||
if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 2 - @ptrToInt(comp_dn.ptr);
|
||||
if (j >= msg.len) return error.InvalidDnsPacket;
|
||||
p = msg.ptr + j;
|
||||
} else if (p[0] != 0) {
|
||||
if (dest != exp_dn.ptr) {
|
||||
dest.* = '.';
|
||||
dest += 1;
|
||||
}
|
||||
var j = p[0];
|
||||
p += 1;
|
||||
if (j >= @ptrToInt(end) - @ptrToInt(p) or j >= @ptrToInt(dend) - @ptrToInt(dest)) {
|
||||
return error.InvalidDnsPacket;
|
||||
}
|
||||
while (j != 0) {
|
||||
j -= 1;
|
||||
dest.* = p[0];
|
||||
dest += 1;
|
||||
p += 1;
|
||||
}
|
||||
} else {
|
||||
dest.* = 0;
|
||||
if (len == std.math.maxInt(usize)) len = @ptrToInt(p) + 1 - @ptrToInt(comp_dn.ptr);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
return error.InvalidDnsPacket;
|
||||
}
|
||||
|
@ -8,26 +8,34 @@ pub const pid_t = c_int;
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u8;
|
||||
pub const socklen_t = u32;
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
pub const sockaddr = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
data: [14]u8,
|
||||
};
|
||||
pub const sockaddr_in = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
len: u8 = @sizeOf(sockaddr_in),
|
||||
family: sa_family_t = AF_INET,
|
||||
port: in_port_t,
|
||||
addr: u32,
|
||||
zero: [8]u8,
|
||||
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
len: u8 = @sizeOf(sockaddr_in6),
|
||||
family: sa_family_t = AF_INET6,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: [16]u8,
|
||||
scope_id: u32,
|
||||
};
|
||||
|
||||
/// UNIX domain socket
|
||||
pub const sockaddr_un = extern struct {
|
||||
len: u8 = @sizeOf(sockaddr_un),
|
||||
family: sa_family_t = AF_UNIX,
|
||||
path: [104]u8,
|
||||
};
|
||||
|
||||
pub const timeval = extern struct {
|
||||
tv_sec: c_long,
|
||||
tv_usec: i32,
|
||||
@ -1196,3 +1204,14 @@ pub const AT_SYMLINK_FOLLOW = 0x0040;
|
||||
|
||||
/// Path refers to directory
|
||||
pub const AT_REMOVEDIR = 0x0080;
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: i32,
|
||||
family: i32,
|
||||
socktype: i32,
|
||||
protocol: i32,
|
||||
addrlen: socklen_t,
|
||||
canonname: ?[*]u8,
|
||||
addr: ?*sockaddr,
|
||||
next: ?*addrinfo,
|
||||
};
|
||||
|
@ -141,28 +141,40 @@ pub const dirent = extern struct {
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u16;
|
||||
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
pub const sockaddr = extern struct {
|
||||
/// total length
|
||||
len: u8,
|
||||
|
||||
/// address family
|
||||
family: sa_family_t,
|
||||
|
||||
/// actually longer; address value
|
||||
data: [14]u8,
|
||||
};
|
||||
|
||||
pub const sockaddr_in = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
len: u8 = @sizeOf(sockaddr_in),
|
||||
family: sa_family_t = AF_INET,
|
||||
port: in_port_t,
|
||||
addr: [16]u8,
|
||||
zero: [8]u8,
|
||||
addr: u32,
|
||||
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
len: u8 = @sizeOf(sockaddr_in6),
|
||||
family: sa_family_t = AF_INET6,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: [16]u8,
|
||||
scope_id: u32,
|
||||
};
|
||||
|
||||
pub const sockaddr_un = extern struct {
|
||||
len: u8 = @sizeOf(sockaddr_un),
|
||||
family: sa_family_t = AF_UNIX,
|
||||
path: [104]u8,
|
||||
};
|
||||
|
||||
pub const CTL_KERN = 1;
|
||||
pub const CTL_DEBUG = 5;
|
||||
|
||||
@ -336,43 +348,6 @@ pub const SOCK_SEQPACKET = 5;
|
||||
pub const SOCK_CLOEXEC = 0x10000000;
|
||||
pub const SOCK_NONBLOCK = 0x20000000;
|
||||
|
||||
pub const PROTO_ip = 0o000;
|
||||
pub const PROTO_icmp = 0o001;
|
||||
pub const PROTO_igmp = 0o002;
|
||||
pub const PROTO_ggp = 0o003;
|
||||
pub const PROTO_ipencap = 0o004;
|
||||
pub const PROTO_st = 0o005;
|
||||
pub const PROTO_tcp = 0o006;
|
||||
pub const PROTO_egp = 0o010;
|
||||
pub const PROTO_pup = 0o014;
|
||||
pub const PROTO_udp = 0o021;
|
||||
pub const PROTO_hmp = 0o024;
|
||||
pub const PROTO_xns_idp = 0o026;
|
||||
pub const PROTO_rdp = 0o033;
|
||||
pub const PROTO_iso_tp4 = 0o035;
|
||||
pub const PROTO_xtp = 0o044;
|
||||
pub const PROTO_ddp = 0o045;
|
||||
pub const PROTO_idpr_cmtp = 0o046;
|
||||
pub const PROTO_ipv6 = 0o051;
|
||||
pub const PROTO_ipv6_route = 0o053;
|
||||
pub const PROTO_ipv6_frag = 0o054;
|
||||
pub const PROTO_idrp = 0o055;
|
||||
pub const PROTO_rsvp = 0o056;
|
||||
pub const PROTO_gre = 0o057;
|
||||
pub const PROTO_esp = 0o062;
|
||||
pub const PROTO_ah = 0o063;
|
||||
pub const PROTO_skip = 0o071;
|
||||
pub const PROTO_ipv6_icmp = 0o072;
|
||||
pub const PROTO_ipv6_nonxt = 0o073;
|
||||
pub const PROTO_ipv6_opts = 0o074;
|
||||
pub const PROTO_rspf = 0o111;
|
||||
pub const PROTO_vmtp = 0o121;
|
||||
pub const PROTO_ospf = 0o131;
|
||||
pub const PROTO_ipip = 0o136;
|
||||
pub const PROTO_encap = 0o142;
|
||||
pub const PROTO_pim = 0o147;
|
||||
pub const PROTO_raw = 0o377;
|
||||
|
||||
pub const PF_UNSPEC = 0;
|
||||
pub const PF_LOCAL = 1;
|
||||
pub const PF_UNIX = PF_LOCAL;
|
||||
@ -963,3 +938,351 @@ pub const AT_REMOVEDIR = 0x0800;
|
||||
|
||||
/// Fail if not under dirfd
|
||||
pub const AT_BENEATH = 0x1000;
|
||||
|
||||
/// dummy for IP
|
||||
pub const IPPROTO_IP = 0;
|
||||
|
||||
/// control message protocol
|
||||
pub const IPPROTO_ICMP = 1;
|
||||
|
||||
/// tcp
|
||||
pub const IPPROTO_TCP = 6;
|
||||
|
||||
/// user datagram protocol
|
||||
pub const IPPROTO_UDP = 17;
|
||||
|
||||
/// IP6 header
|
||||
pub const IPPROTO_IPV6 = 41;
|
||||
|
||||
/// raw IP packet
|
||||
pub const IPPROTO_RAW = 255;
|
||||
|
||||
/// IP6 hop-by-hop options
|
||||
pub const IPPROTO_HOPOPTS = 0;
|
||||
|
||||
/// group mgmt protocol
|
||||
pub const IPPROTO_IGMP = 2;
|
||||
|
||||
/// gateway^2 (deprecated)
|
||||
pub const IPPROTO_GGP = 3;
|
||||
|
||||
/// IPv4 encapsulation
|
||||
pub const IPPROTO_IPV4 = 4;
|
||||
|
||||
/// for compatibility
|
||||
pub const IPPROTO_IPIP = IPPROTO_IPV4;
|
||||
|
||||
/// Stream protocol II
|
||||
pub const IPPROTO_ST = 7;
|
||||
|
||||
/// exterior gateway protocol
|
||||
pub const IPPROTO_EGP = 8;
|
||||
|
||||
/// private interior gateway
|
||||
pub const IPPROTO_PIGP = 9;
|
||||
|
||||
/// BBN RCC Monitoring
|
||||
pub const IPPROTO_RCCMON = 10;
|
||||
|
||||
/// network voice protocol
|
||||
pub const IPPROTO_NVPII = 11;
|
||||
|
||||
/// pup
|
||||
pub const IPPROTO_PUP = 12;
|
||||
|
||||
/// Argus
|
||||
pub const IPPROTO_ARGUS = 13;
|
||||
|
||||
/// EMCON
|
||||
pub const IPPROTO_EMCON = 14;
|
||||
|
||||
/// Cross Net Debugger
|
||||
pub const IPPROTO_XNET = 15;
|
||||
|
||||
/// Chaos
|
||||
pub const IPPROTO_CHAOS = 16;
|
||||
|
||||
/// Multiplexing
|
||||
pub const IPPROTO_MUX = 18;
|
||||
|
||||
/// DCN Measurement Subsystems
|
||||
pub const IPPROTO_MEAS = 19;
|
||||
|
||||
/// Host Monitoring
|
||||
pub const IPPROTO_HMP = 20;
|
||||
|
||||
/// Packet Radio Measurement
|
||||
pub const IPPROTO_PRM = 21;
|
||||
|
||||
/// xns idp
|
||||
pub const IPPROTO_IDP = 22;
|
||||
|
||||
/// Trunk-1
|
||||
pub const IPPROTO_TRUNK1 = 23;
|
||||
|
||||
/// Trunk-2
|
||||
pub const IPPROTO_TRUNK2 = 24;
|
||||
|
||||
/// Leaf-1
|
||||
pub const IPPROTO_LEAF1 = 25;
|
||||
|
||||
/// Leaf-2
|
||||
pub const IPPROTO_LEAF2 = 26;
|
||||
|
||||
/// Reliable Data
|
||||
pub const IPPROTO_RDP = 27;
|
||||
|
||||
/// Reliable Transaction
|
||||
pub const IPPROTO_IRTP = 28;
|
||||
|
||||
/// tp-4 w/ class negotiation
|
||||
pub const IPPROTO_TP = 29;
|
||||
|
||||
/// Bulk Data Transfer
|
||||
pub const IPPROTO_BLT = 30;
|
||||
|
||||
/// Network Services
|
||||
pub const IPPROTO_NSP = 31;
|
||||
|
||||
/// Merit Internodal
|
||||
pub const IPPROTO_INP = 32;
|
||||
|
||||
/// Datagram Congestion Control Protocol
|
||||
pub const IPPROTO_DCCP = 33;
|
||||
|
||||
/// Third Party Connect
|
||||
pub const IPPROTO_3PC = 34;
|
||||
|
||||
/// InterDomain Policy Routing
|
||||
pub const IPPROTO_IDPR = 35;
|
||||
|
||||
/// XTP
|
||||
pub const IPPROTO_XTP = 36;
|
||||
|
||||
/// Datagram Delivery
|
||||
pub const IPPROTO_DDP = 37;
|
||||
|
||||
/// Control Message Transport
|
||||
pub const IPPROTO_CMTP = 38;
|
||||
|
||||
/// TP++ Transport
|
||||
pub const IPPROTO_TPXX = 39;
|
||||
|
||||
/// IL transport protocol
|
||||
pub const IPPROTO_IL = 40;
|
||||
|
||||
/// Source Demand Routing
|
||||
pub const IPPROTO_SDRP = 42;
|
||||
|
||||
/// IP6 routing header
|
||||
pub const IPPROTO_ROUTING = 43;
|
||||
|
||||
/// IP6 fragmentation header
|
||||
pub const IPPROTO_FRAGMENT = 44;
|
||||
|
||||
/// InterDomain Routing
|
||||
pub const IPPROTO_IDRP = 45;
|
||||
|
||||
/// resource reservation
|
||||
pub const IPPROTO_RSVP = 46;
|
||||
|
||||
/// General Routing Encap.
|
||||
pub const IPPROTO_GRE = 47;
|
||||
|
||||
/// Mobile Host Routing
|
||||
pub const IPPROTO_MHRP = 48;
|
||||
|
||||
/// BHA
|
||||
pub const IPPROTO_BHA = 49;
|
||||
|
||||
/// IP6 Encap Sec. Payload
|
||||
pub const IPPROTO_ESP = 50;
|
||||
|
||||
/// IP6 Auth Header
|
||||
pub const IPPROTO_AH = 51;
|
||||
|
||||
/// Integ. Net Layer Security
|
||||
pub const IPPROTO_INLSP = 52;
|
||||
|
||||
/// IP with encryption
|
||||
pub const IPPROTO_SWIPE = 53;
|
||||
|
||||
/// Next Hop Resolution
|
||||
pub const IPPROTO_NHRP = 54;
|
||||
|
||||
/// IP Mobility
|
||||
pub const IPPROTO_MOBILE = 55;
|
||||
|
||||
/// Transport Layer Security
|
||||
pub const IPPROTO_TLSP = 56;
|
||||
|
||||
/// SKIP
|
||||
pub const IPPROTO_SKIP = 57;
|
||||
|
||||
/// ICMP6
|
||||
pub const IPPROTO_ICMPV6 = 58;
|
||||
|
||||
/// IP6 no next header
|
||||
pub const IPPROTO_NONE = 59;
|
||||
|
||||
/// IP6 destination option
|
||||
pub const IPPROTO_DSTOPTS = 60;
|
||||
|
||||
/// any host internal protocol
|
||||
pub const IPPROTO_AHIP = 61;
|
||||
|
||||
/// CFTP
|
||||
pub const IPPROTO_CFTP = 62;
|
||||
|
||||
/// "hello" routing protocol
|
||||
pub const IPPROTO_HELLO = 63;
|
||||
|
||||
/// SATNET/Backroom EXPAK
|
||||
pub const IPPROTO_SATEXPAK = 64;
|
||||
|
||||
/// Kryptolan
|
||||
pub const IPPROTO_KRYPTOLAN = 65;
|
||||
|
||||
/// Remote Virtual Disk
|
||||
pub const IPPROTO_RVD = 66;
|
||||
|
||||
/// Pluribus Packet Core
|
||||
pub const IPPROTO_IPPC = 67;
|
||||
|
||||
/// Any distributed FS
|
||||
pub const IPPROTO_ADFS = 68;
|
||||
|
||||
/// Satnet Monitoring
|
||||
pub const IPPROTO_SATMON = 69;
|
||||
|
||||
/// VISA Protocol
|
||||
pub const IPPROTO_VISA = 70;
|
||||
|
||||
/// Packet Core Utility
|
||||
pub const IPPROTO_IPCV = 71;
|
||||
|
||||
/// Comp. Prot. Net. Executive
|
||||
pub const IPPROTO_CPNX = 72;
|
||||
|
||||
/// Comp. Prot. HeartBeat
|
||||
pub const IPPROTO_CPHB = 73;
|
||||
|
||||
/// Wang Span Network
|
||||
pub const IPPROTO_WSN = 74;
|
||||
|
||||
/// Packet Video Protocol
|
||||
pub const IPPROTO_PVP = 75;
|
||||
|
||||
/// BackRoom SATNET Monitoring
|
||||
pub const IPPROTO_BRSATMON = 76;
|
||||
|
||||
/// Sun net disk proto (temp.)
|
||||
pub const IPPROTO_ND = 77;
|
||||
|
||||
/// WIDEBAND Monitoring
|
||||
pub const IPPROTO_WBMON = 78;
|
||||
|
||||
/// WIDEBAND EXPAK
|
||||
pub const IPPROTO_WBEXPAK = 79;
|
||||
|
||||
/// ISO cnlp
|
||||
pub const IPPROTO_EON = 80;
|
||||
|
||||
/// VMTP
|
||||
pub const IPPROTO_VMTP = 81;
|
||||
|
||||
/// Secure VMTP
|
||||
pub const IPPROTO_SVMTP = 82;
|
||||
|
||||
/// Banyon VINES
|
||||
pub const IPPROTO_VINES = 83;
|
||||
|
||||
/// TTP
|
||||
pub const IPPROTO_TTP = 84;
|
||||
|
||||
/// NSFNET-IGP
|
||||
pub const IPPROTO_IGP = 85;
|
||||
|
||||
/// dissimilar gateway prot.
|
||||
pub const IPPROTO_DGP = 86;
|
||||
|
||||
/// TCF
|
||||
pub const IPPROTO_TCF = 87;
|
||||
|
||||
/// Cisco/GXS IGRP
|
||||
pub const IPPROTO_IGRP = 88;
|
||||
|
||||
/// OSPFIGP
|
||||
pub const IPPROTO_OSPFIGP = 89;
|
||||
|
||||
/// Strite RPC protocol
|
||||
pub const IPPROTO_SRPC = 90;
|
||||
|
||||
/// Locus Address Resoloution
|
||||
pub const IPPROTO_LARP = 91;
|
||||
|
||||
/// Multicast Transport
|
||||
pub const IPPROTO_MTP = 92;
|
||||
|
||||
/// AX.25 Frames
|
||||
pub const IPPROTO_AX25 = 93;
|
||||
|
||||
/// IP encapsulated in IP
|
||||
pub const IPPROTO_IPEIP = 94;
|
||||
|
||||
/// Mobile Int.ing control
|
||||
pub const IPPROTO_MICP = 95;
|
||||
|
||||
/// Semaphore Comm. security
|
||||
pub const IPPROTO_SCCSP = 96;
|
||||
|
||||
/// Ethernet IP encapsulation
|
||||
pub const IPPROTO_ETHERIP = 97;
|
||||
|
||||
/// encapsulation header
|
||||
pub const IPPROTO_ENCAP = 98;
|
||||
|
||||
/// any private encr. scheme
|
||||
pub const IPPROTO_APES = 99;
|
||||
|
||||
/// GMTP
|
||||
pub const IPPROTO_GMTP = 100;
|
||||
|
||||
/// payload compression (IPComp)
|
||||
pub const IPPROTO_IPCOMP = 108;
|
||||
|
||||
/// SCTP
|
||||
pub const IPPROTO_SCTP = 132;
|
||||
|
||||
/// IPv6 Mobility Header
|
||||
pub const IPPROTO_MH = 135;
|
||||
|
||||
/// UDP-Lite
|
||||
pub const IPPROTO_UDPLITE = 136;
|
||||
|
||||
/// IP6 Host Identity Protocol
|
||||
pub const IPPROTO_HIP = 139;
|
||||
|
||||
/// IP6 Shim6 Protocol
|
||||
pub const IPPROTO_SHIM6 = 140;
|
||||
|
||||
/// Protocol Independent Mcast
|
||||
pub const IPPROTO_PIM = 103;
|
||||
|
||||
/// CARP
|
||||
pub const IPPROTO_CARP = 112;
|
||||
|
||||
/// PGM
|
||||
pub const IPPROTO_PGM = 113;
|
||||
|
||||
/// MPLS-in-IP
|
||||
pub const IPPROTO_MPLS = 137;
|
||||
|
||||
/// PFSYNC
|
||||
pub const IPPROTO_PFSYNC = 240;
|
||||
|
||||
/// Reserved
|
||||
pub const IPPROTO_RESERVED_253 = 253;
|
||||
|
||||
/// Reserved
|
||||
pub const IPPROTO_RESERVED_254 = 254;
|
||||
|
@ -227,43 +227,6 @@ pub const SEEK_SET = 0;
|
||||
pub const SEEK_CUR = 1;
|
||||
pub const SEEK_END = 2;
|
||||
|
||||
pub const PROTO_ip = 0o000;
|
||||
pub const PROTO_icmp = 0o001;
|
||||
pub const PROTO_igmp = 0o002;
|
||||
pub const PROTO_ggp = 0o003;
|
||||
pub const PROTO_ipencap = 0o004;
|
||||
pub const PROTO_st = 0o005;
|
||||
pub const PROTO_tcp = 0o006;
|
||||
pub const PROTO_egp = 0o010;
|
||||
pub const PROTO_pup = 0o014;
|
||||
pub const PROTO_udp = 0o021;
|
||||
pub const PROTO_hmp = 0o024;
|
||||
pub const PROTO_xns_idp = 0o026;
|
||||
pub const PROTO_rdp = 0o033;
|
||||
pub const PROTO_iso_tp4 = 0o035;
|
||||
pub const PROTO_xtp = 0o044;
|
||||
pub const PROTO_ddp = 0o045;
|
||||
pub const PROTO_idpr_cmtp = 0o046;
|
||||
pub const PROTO_ipv6 = 0o051;
|
||||
pub const PROTO_ipv6_route = 0o053;
|
||||
pub const PROTO_ipv6_frag = 0o054;
|
||||
pub const PROTO_idrp = 0o055;
|
||||
pub const PROTO_rsvp = 0o056;
|
||||
pub const PROTO_gre = 0o057;
|
||||
pub const PROTO_esp = 0o062;
|
||||
pub const PROTO_ah = 0o063;
|
||||
pub const PROTO_skip = 0o071;
|
||||
pub const PROTO_ipv6_icmp = 0o072;
|
||||
pub const PROTO_ipv6_nonxt = 0o073;
|
||||
pub const PROTO_ipv6_opts = 0o074;
|
||||
pub const PROTO_rspf = 0o111;
|
||||
pub const PROTO_vmtp = 0o121;
|
||||
pub const PROTO_ospf = 0o131;
|
||||
pub const PROTO_ipip = 0o136;
|
||||
pub const PROTO_encap = 0o142;
|
||||
pub const PROTO_pim = 0o147;
|
||||
pub const PROTO_raw = 0o377;
|
||||
|
||||
pub const SHUT_RD = 0;
|
||||
pub const SHUT_WR = 1;
|
||||
pub const SHUT_RDWR = 2;
|
||||
@ -846,30 +809,31 @@ pub const in_port_t = u16;
|
||||
pub const sa_family_t = u16;
|
||||
pub const socklen_t = u32;
|
||||
|
||||
/// This intentionally only has ip4 and ip6
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
un: sockaddr_un,
|
||||
pub const sockaddr = extern struct {
|
||||
family: sa_family_t,
|
||||
data: [14]u8,
|
||||
};
|
||||
|
||||
/// IPv4 socket address
|
||||
pub const sockaddr_in = extern struct {
|
||||
family: sa_family_t,
|
||||
family: sa_family_t = AF_INET,
|
||||
port: in_port_t,
|
||||
addr: u32,
|
||||
zero: [8]u8,
|
||||
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
/// IPv6 socket address
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
family: sa_family_t,
|
||||
family: sa_family_t = AF_INET6,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: [16]u8,
|
||||
scope_id: u32,
|
||||
};
|
||||
|
||||
/// UNIX domain socket address
|
||||
pub const sockaddr_un = extern struct {
|
||||
family: sa_family_t,
|
||||
family: sa_family_t = AF_UNIX,
|
||||
path: [108]u8,
|
||||
};
|
||||
|
||||
@ -1388,3 +1352,70 @@ pub const Statx = extern struct {
|
||||
|
||||
__pad2: [14]u64,
|
||||
};
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: i32,
|
||||
family: i32,
|
||||
socktype: i32,
|
||||
protocol: i32,
|
||||
addrlen: socklen_t,
|
||||
addr: ?*sockaddr,
|
||||
canonname: ?[*]u8,
|
||||
next: ?*addrinfo,
|
||||
};
|
||||
|
||||
pub const IPPORT_RESERVED = 1024;
|
||||
|
||||
pub const IPPROTO_IP = 0;
|
||||
pub const IPPROTO_HOPOPTS = 0;
|
||||
pub const IPPROTO_ICMP = 1;
|
||||
pub const IPPROTO_IGMP = 2;
|
||||
pub const IPPROTO_IPIP = 4;
|
||||
pub const IPPROTO_TCP = 6;
|
||||
pub const IPPROTO_EGP = 8;
|
||||
pub const IPPROTO_PUP = 12;
|
||||
pub const IPPROTO_UDP = 17;
|
||||
pub const IPPROTO_IDP = 22;
|
||||
pub const IPPROTO_TP = 29;
|
||||
pub const IPPROTO_DCCP = 33;
|
||||
pub const IPPROTO_IPV6 = 41;
|
||||
pub const IPPROTO_ROUTING = 43;
|
||||
pub const IPPROTO_FRAGMENT = 44;
|
||||
pub const IPPROTO_RSVP = 46;
|
||||
pub const IPPROTO_GRE = 47;
|
||||
pub const IPPROTO_ESP = 50;
|
||||
pub const IPPROTO_AH = 51;
|
||||
pub const IPPROTO_ICMPV6 = 58;
|
||||
pub const IPPROTO_NONE = 59;
|
||||
pub const IPPROTO_DSTOPTS = 60;
|
||||
pub const IPPROTO_MTP = 92;
|
||||
pub const IPPROTO_BEETPH = 94;
|
||||
pub const IPPROTO_ENCAP = 98;
|
||||
pub const IPPROTO_PIM = 103;
|
||||
pub const IPPROTO_COMP = 108;
|
||||
pub const IPPROTO_SCTP = 132;
|
||||
pub const IPPROTO_MH = 135;
|
||||
pub const IPPROTO_UDPLITE = 136;
|
||||
pub const IPPROTO_MPLS = 137;
|
||||
pub const IPPROTO_RAW = 255;
|
||||
pub const IPPROTO_MAX = 256;
|
||||
|
||||
pub const RR_A = 1;
|
||||
pub const RR_CNAME = 5;
|
||||
pub const RR_AAAA = 28;
|
||||
|
||||
pub const nfds_t = usize;
|
||||
pub const pollfd = extern struct {
|
||||
fd: fd_t,
|
||||
events: i16,
|
||||
revents: i16,
|
||||
};
|
||||
|
||||
pub const POLLIN = 0x001;
|
||||
pub const POLLPRI = 0x002;
|
||||
pub const POLLOUT = 0x004;
|
||||
pub const POLLERR = 0x008;
|
||||
pub const POLLHUP = 0x010;
|
||||
pub const POLLNVAL = 0x020;
|
||||
pub const POLLRDNORM = 0x040;
|
||||
pub const POLLRDBAND = 0x080;
|
||||
|
@ -137,21 +137,27 @@ pub const dirent = extern struct {
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u8;
|
||||
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
pub const sockaddr = extern struct {
|
||||
/// total length
|
||||
len: u8,
|
||||
|
||||
/// address family
|
||||
family: sa_family_t,
|
||||
|
||||
/// actually longer; address value
|
||||
data: [14]u8,
|
||||
};
|
||||
|
||||
pub const sockaddr_in = extern struct {
|
||||
len: u8,
|
||||
len: u8 = @sizeOf(sockaddr_in),
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
addr: u32,
|
||||
zero: [8]u8,
|
||||
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
len: u8,
|
||||
len: u8 = @sizeOf(sockaddr_in6),
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
@ -159,6 +165,18 @@ pub const sockaddr_in6 = extern struct {
|
||||
scope_id: u32,
|
||||
};
|
||||
|
||||
/// Definitions for UNIX IPC domain.
|
||||
pub const sockaddr_un = extern struct {
|
||||
/// total sockaddr length
|
||||
len: u8 = @sizeOf(sockaddr_un),
|
||||
|
||||
/// AF_LOCAL
|
||||
family: sa_family_t,
|
||||
|
||||
/// path name
|
||||
path: [104]u8,
|
||||
};
|
||||
|
||||
pub const CTL_KERN = 1;
|
||||
pub const CTL_DEBUG = 5;
|
||||
|
||||
@ -316,31 +334,6 @@ pub const SOCK_SEQPACKET = 5;
|
||||
pub const SOCK_CLOEXEC = 0x10000000;
|
||||
pub const SOCK_NONBLOCK = 0x20000000;
|
||||
|
||||
pub const PROTO_ip = 0;
|
||||
pub const PROTO_icmp = 1;
|
||||
pub const PROTO_igmp = 2;
|
||||
pub const PROTO_ggp = 3;
|
||||
pub const PROTO_ipencap = 4;
|
||||
pub const PROTO_tcp = 6;
|
||||
pub const PROTO_egp = 8;
|
||||
pub const PROTO_pup = 12;
|
||||
pub const PROTO_udp = 17;
|
||||
pub const PROTO_xns_idp = 22;
|
||||
pub const PROTO_iso_tp4 = 29;
|
||||
pub const PROTO_ipv6 = 41;
|
||||
pub const PROTO_ipv6_route = 43;
|
||||
pub const PROTO_ipv6_frag = 44;
|
||||
pub const PROTO_rsvp = 46;
|
||||
pub const PROTO_gre = 47;
|
||||
pub const PROTO_esp = 50;
|
||||
pub const PROTO_ah = 51;
|
||||
pub const PROTO_ipv6_icmp = 58;
|
||||
pub const PROTO_ipv6_nonxt = 59;
|
||||
pub const PROTO_ipv6_opts = 60;
|
||||
pub const PROTO_encap = 98;
|
||||
pub const PROTO_pim = 103;
|
||||
pub const PROTO_raw = 255;
|
||||
|
||||
pub const PF_UNSPEC = 0;
|
||||
pub const PF_LOCAL = 1;
|
||||
pub const PF_UNIX = PF_LOCAL;
|
||||
@ -827,3 +820,114 @@ pub fn S_IWHT(m: u32) bool {
|
||||
}
|
||||
|
||||
pub const HOST_NAME_MAX = 255;
|
||||
|
||||
/// dummy for IP
|
||||
pub const IPPROTO_IP = 0;
|
||||
|
||||
/// IP6 hop-by-hop options
|
||||
pub const IPPROTO_HOPOPTS = 0;
|
||||
|
||||
/// control message protocol
|
||||
pub const IPPROTO_ICMP = 1;
|
||||
|
||||
/// group mgmt protocol
|
||||
pub const IPPROTO_IGMP = 2;
|
||||
|
||||
/// gateway^2 (deprecated)
|
||||
pub const IPPROTO_GGP = 3;
|
||||
|
||||
/// IP header
|
||||
pub const IPPROTO_IPV4 = 4;
|
||||
|
||||
/// IP inside IP
|
||||
pub const IPPROTO_IPIP = 4;
|
||||
|
||||
/// tcp
|
||||
pub const IPPROTO_TCP = 6;
|
||||
|
||||
/// exterior gateway protocol
|
||||
pub const IPPROTO_EGP = 8;
|
||||
|
||||
/// pup
|
||||
pub const IPPROTO_PUP = 12;
|
||||
|
||||
/// user datagram protocol
|
||||
pub const IPPROTO_UDP = 17;
|
||||
|
||||
/// xns idp
|
||||
pub const IPPROTO_IDP = 22;
|
||||
|
||||
/// tp-4 w/ class negotiation
|
||||
pub const IPPROTO_TP = 29;
|
||||
|
||||
/// DCCP
|
||||
pub const IPPROTO_DCCP = 33;
|
||||
|
||||
/// IP6 header
|
||||
pub const IPPROTO_IPV6 = 41;
|
||||
|
||||
/// IP6 routing header
|
||||
pub const IPPROTO_ROUTING = 43;
|
||||
|
||||
/// IP6 fragmentation header
|
||||
pub const IPPROTO_FRAGMENT = 44;
|
||||
|
||||
/// resource reservation
|
||||
pub const IPPROTO_RSVP = 46;
|
||||
|
||||
/// GRE encaps RFC 1701
|
||||
pub const IPPROTO_GRE = 47;
|
||||
|
||||
/// encap. security payload
|
||||
pub const IPPROTO_ESP = 50;
|
||||
|
||||
/// authentication header
|
||||
pub const IPPROTO_AH = 51;
|
||||
|
||||
/// IP Mobility RFC 2004
|
||||
pub const IPPROTO_MOBILE = 55;
|
||||
|
||||
/// IPv6 ICMP
|
||||
pub const IPPROTO_IPV6_ICMP = 58;
|
||||
|
||||
/// ICMP6
|
||||
pub const IPPROTO_ICMPV6 = 58;
|
||||
|
||||
/// IP6 no next header
|
||||
pub const IPPROTO_NONE = 59;
|
||||
|
||||
/// IP6 destination option
|
||||
pub const IPPROTO_DSTOPTS = 60;
|
||||
|
||||
/// ISO cnlp
|
||||
pub const IPPROTO_EON = 80;
|
||||
|
||||
/// Ethernet-in-IP
|
||||
pub const IPPROTO_ETHERIP = 97;
|
||||
|
||||
/// encapsulation header
|
||||
pub const IPPROTO_ENCAP = 98;
|
||||
|
||||
/// Protocol indep. multicast
|
||||
pub const IPPROTO_PIM = 103;
|
||||
|
||||
/// IP Payload Comp. Protocol
|
||||
pub const IPPROTO_IPCOMP = 108;
|
||||
|
||||
/// VRRP RFC 2338
|
||||
pub const IPPROTO_VRRP = 112;
|
||||
|
||||
/// Common Address Resolution Protocol
|
||||
pub const IPPROTO_CARP = 112;
|
||||
|
||||
/// L2TPv3
|
||||
pub const IPPROTO_L2TP = 115;
|
||||
|
||||
/// SCTP
|
||||
pub const IPPROTO_SCTP = 132;
|
||||
|
||||
/// PFSYNC
|
||||
pub const IPPROTO_PFSYNC = 240;
|
||||
|
||||
/// raw IP packet
|
||||
pub const IPPROTO_RAW = 255;
|
||||
|
@ -161,3 +161,63 @@ pub const F_OK = 0;
|
||||
|
||||
/// Remove directory instead of unlinking file
|
||||
pub const AT_REMOVEDIR = 0x200;
|
||||
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u16;
|
||||
pub const socklen_t = u32;
|
||||
|
||||
pub const sockaddr = extern struct {
|
||||
family: sa_family_t,
|
||||
data: [14]u8,
|
||||
};
|
||||
pub const sockaddr_in = extern struct {
|
||||
family: sa_family_t = AF_INET,
|
||||
port: in_port_t,
|
||||
addr: in_addr,
|
||||
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
family: sa_family_t = AF_INET6,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: in6_addr,
|
||||
scope_id: u32,
|
||||
};
|
||||
pub const in6_addr = [16]u8;
|
||||
pub const in_addr = u32;
|
||||
|
||||
pub const AF_UNSPEC = 0;
|
||||
pub const AF_UNIX = 1;
|
||||
pub const AF_INET = 2;
|
||||
pub const AF_IMPLINK = 3;
|
||||
pub const AF_PUP = 4;
|
||||
pub const AF_CHAOS = 5;
|
||||
pub const AF_NS = 6;
|
||||
pub const AF_IPX = AF_NS;
|
||||
pub const AF_ISO = 7;
|
||||
pub const AF_OSI = AF_ISO;
|
||||
pub const AF_ECMA = 8;
|
||||
pub const AF_DATAKIT = 9;
|
||||
pub const AF_CCITT = 10;
|
||||
pub const AF_SNA = 11;
|
||||
pub const AF_DECnet = 12;
|
||||
pub const AF_DLI = 13;
|
||||
pub const AF_LAT = 14;
|
||||
pub const AF_HYLINK = 15;
|
||||
pub const AF_APPLETALK = 16;
|
||||
pub const AF_NETBIOS = 17;
|
||||
pub const AF_VOICEVIEW = 18;
|
||||
pub const AF_FIREFOX = 19;
|
||||
pub const AF_UNKNOWN1 = 20;
|
||||
pub const AF_BAN = 21;
|
||||
pub const AF_ATM = 22;
|
||||
pub const AF_INET6 = 23;
|
||||
pub const AF_CLUSTER = 24;
|
||||
pub const AF_12844 = 25;
|
||||
pub const AF_IRDA = 26;
|
||||
pub const AF_NETDES = 28;
|
||||
pub const AF_TCNPROCESS = 29;
|
||||
pub const AF_TCNMESSAGE = 30;
|
||||
pub const AF_ICLFXBM = 31;
|
||||
pub const AF_BTH = 32;
|
||||
pub const AF_MAX = 33;
|
||||
|
@ -226,6 +226,28 @@ pub fn munmap(address: [*]const u8, length: usize) usize {
|
||||
return syscall2(SYS_munmap, @ptrToInt(address), length);
|
||||
}
|
||||
|
||||
pub fn poll(fds: [*]pollfd, n: nfds_t, timeout: i32) usize {
|
||||
if (@hasDecl(@This(), "SYS_poll")) {
|
||||
return syscall3(SYS_poll, @ptrToInt(fds), n, @bitCast(u32, timeout));
|
||||
} else {
|
||||
return syscall6(
|
||||
SYS_ppoll,
|
||||
@ptrToInt(fds),
|
||||
n,
|
||||
@ptrToInt(if (timeout >= 0)
|
||||
×pec{
|
||||
.tv_sec = @divTrunc(timeout, 1000),
|
||||
.tv_nsec = @rem(timeout, 1000) * 1000000,
|
||||
}
|
||||
else
|
||||
null),
|
||||
0,
|
||||
0,
|
||||
NSIG / 8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
|
||||
return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
|
||||
}
|
||||
|
@ -205,6 +205,8 @@ pub const Target = union(enum) {
|
||||
},
|
||||
};
|
||||
|
||||
pub const stack_align = 16;
|
||||
|
||||
pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
|
||||
return std.fmt.allocPrint(
|
||||
allocator,
|
||||
|
@ -128,6 +128,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error
|
||||
export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
|
||||
const c_out_stream = &std.io.COutStream.init(output_file).stream;
|
||||
_ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
|
||||
error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
|
||||
error.SystemResources => return Error.SystemResources,
|
||||
error.OperationAborted => return Error.OperationAborted,
|
||||
error.BrokenPipe => return Error.BrokenPipe,
|
||||
|
@ -151,18 +151,22 @@ pub fn translate(
|
||||
};
|
||||
defer ZigClangASTUnit_delete(ast_unit);
|
||||
|
||||
var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
|
||||
errdefer tree_arena.deinit();
|
||||
const tree = blk: {
|
||||
var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
|
||||
errdefer tree_arena.deinit();
|
||||
|
||||
const tree = try tree_arena.allocator.create(ast.Tree);
|
||||
tree.* = ast.Tree{
|
||||
.source = undefined, // need to use Buffer.toOwnedSlice later
|
||||
.root_node = undefined,
|
||||
.arena_allocator = tree_arena,
|
||||
.tokens = undefined, // can't reference the allocator yet
|
||||
.errors = undefined, // can't reference the allocator yet
|
||||
const tree = try tree_arena.allocator.create(ast.Tree);
|
||||
tree.* = ast.Tree{
|
||||
.source = undefined, // need to use Buffer.toOwnedSlice later
|
||||
.root_node = undefined,
|
||||
.arena_allocator = tree_arena,
|
||||
.tokens = undefined, // can't reference the allocator yet
|
||||
.errors = undefined, // can't reference the allocator yet
|
||||
};
|
||||
break :blk tree;
|
||||
};
|
||||
const arena = &tree.arena_allocator.allocator; // now we can reference the allocator
|
||||
errdefer tree.arena_allocator.deinit();
|
||||
tree.tokens = ast.Tree.TokenList.init(arena);
|
||||
tree.errors = ast.Tree.ErrorList.init(arena);
|
||||
|
||||
|
@ -4381,6 +4381,10 @@ static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode
|
||||
if (callee->anal_state == FnAnalStateComplete) {
|
||||
analyze_fn_async(g, callee, true);
|
||||
if (callee->anal_state == FnAnalStateInvalid) {
|
||||
if (g->trace_err != nullptr) {
|
||||
g->trace_err = add_error_note(g, g->trace_err, call_node,
|
||||
buf_sprintf("while checking if '%s' is async", buf_ptr(&fn->symbol_name)));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
callee_is_async = fn_is_async(callee);
|
||||
@ -6128,6 +6132,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
param_name = buf_sprintf("@arg%" ZIG_PRI_usize, arg_i);
|
||||
}
|
||||
ZigType *param_type = param_info->type;
|
||||
if ((err = type_resolve(g, param_type, ResolveStatusSizeKnown))) {
|
||||
return err;
|
||||
}
|
||||
|
||||
fields.append({buf_ptr(param_name), param_type, 0});
|
||||
}
|
||||
@ -7538,7 +7545,9 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
|
||||
|
||||
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field) {
|
||||
assert(struct_type->id == ZigTypeIdStruct);
|
||||
assert(type_is_resolved(struct_type, ResolveStatusSizeKnown));
|
||||
if (struct_type->data.structure.layout != ContainerLayoutAuto) {
|
||||
assert(type_is_resolved(struct_type, ResolveStatusSizeKnown));
|
||||
}
|
||||
if (struct_type->data.structure.host_int_bytes == nullptr)
|
||||
return 0;
|
||||
return struct_type->data.structure.host_int_bytes[field->gen_index];
|
||||
|
13
src/ir.cpp
13
src/ir.cpp
@ -17692,7 +17692,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
|
||||
{
|
||||
size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
|
||||
uint64_t new_index = offset + index;
|
||||
assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len);
|
||||
ir_assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len,
|
||||
&elem_ptr_instruction->base);
|
||||
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
out_val->data.x_ptr.data.base_array.array_val =
|
||||
ptr_field->data.x_ptr.data.base_array.array_val;
|
||||
@ -17854,7 +17855,10 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
|
||||
case OnePossibleValueNo:
|
||||
break;
|
||||
}
|
||||
if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusAlignmentKnown)))
|
||||
ResolveStatus needed_resolve_status =
|
||||
(struct_type->data.structure.layout == ContainerLayoutAuto) ?
|
||||
ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown;
|
||||
if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
assert(struct_ptr->value.type->id == ZigTypeIdPointer);
|
||||
uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host;
|
||||
@ -17873,6 +17877,9 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
|
||||
if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusSizeKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
|
||||
if (struct_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -17919,7 +17926,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
Error err;
|
||||
|
||||
ZigType *bare_type = container_ref_type(container_type);
|
||||
if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusSizeKnown)))
|
||||
if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
assert(container_ptr->value.type->id == ZigTypeIdPointer);
|
||||
|
@ -162,9 +162,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const obj = AstObject{ .lhsExpr = lhsExpr };
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",
|
||||
"tmp.zig:5:5: note: while checking this field",
|
||||
"tmp.zig:4:19: error: union 'AstObject' depends on itself",
|
||||
"tmp.zig:2:5: note: while checking this field",
|
||||
"tmp.zig:5:5: note: while checking this field",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
Loading…
Reference in New Issue
Block a user