commit 098879d7cd61043130abc1125ec63a1b564e9e31
parent 31b5c8a01444a2db589a30b0ed81ffb37b547a4c
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 4 Sep 2021 10:48:17 +0200
Remove os::streamfd, update net::*, unix::*
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
20 files changed, 65 insertions(+), 215 deletions(-)
diff --git a/io/+linux/file.ha b/io/+linux/file.ha
@@ -48,9 +48,17 @@ export fn is_file(s: *stream) bool = {
|| s.copier == &fd_copy;
};
-// Returns the file descriptor for a given [[file]]. This function is not
+// Returns the file descriptor for a given [[file]] or [[stream]]. In the latter
+// case, a non-file input will cause the program to abort. This function is not
// portable.
-export fn fd(f: *file) int = f.fd;
+export fn fd(f: (*file | *stream)) int = match (f) {
+ f: *file => f.fd,
+ f: *stream => {
+ assert(is_file(f));
+ let f = f: *file;
+ yield f.fd;
+ },
+};
fn fd_read(s: *stream, buf: []u8) (size | EOF | error) = {
let stream = s: *file;
diff --git a/net/+linux.ha b/net/+linux.ha
@@ -19,7 +19,7 @@ export fn listenerfd(l: *listener) (int | void) = {
};
};
-export fn stream_accept(l: *listener) (*io::stream | error) = {
+export fn stream_accept(l: *listener) (io::file | error) = {
assert(l.accept == &stream_accept);
let l = l: *stream_listener;
let sn = rt::sockaddr {...};
@@ -30,9 +30,9 @@ export fn stream_accept(l: *listener) (*io::stream | error) = {
};
static let namebuf: [32]u8 = [0...];
- return alloc(os::fdopen(fd,
- fmt::bsprintf(namebuf, "<net connection {}>", fd),
- io::mode::READ | io::mode::WRITE));
+ return io::fdopen(fd,
+ fmt::bsprintf(namebuf, "<network fd {}>", fd),
+ io::mode::READ | io::mode::WRITE);
};
export fn stream_shutdown(l: *listener) void = {
diff --git a/net/dial/dial.ha b/net/dial/dial.ha
@@ -33,7 +33,7 @@ export fn dial(
proto: str,
address: str,
service: str,
-) (*io::stream | error) = {
+) (io::file | error) = {
for (let i = 0z; i < len(default_protocols); i += 1) {
const p = default_protocols[i];
if (p.name == proto) {
diff --git a/net/dial/ip.ha b/net/dial/ip.ha
@@ -3,14 +3,15 @@ use net;
use net::ip;
use net::tcp;
use net::udp;
+use io;
-fn dial_tcp(addr: str, service: str) (*io::stream | error) = {
+fn dial_tcp(addr: str, service: str) (io::file | error) = {
const result = resolve("tcp", addr, service)?;
const addrs = result.0, port = result.1;
for (let i = 0z; i < len(addrs); i += 1) {
const addr = addrs[i];
match (tcp::connect(addr, port)) {
- conn: *io::stream => return conn,
+ conn: io::file => return conn,
err: net::error => if (i + 1 >= len(addrs)) {
return err;
},
@@ -19,13 +20,13 @@ fn dial_tcp(addr: str, service: str) (*io::stream | error) = {
abort(); // Unreachable
};
-fn dial_udp(addr: str, service: str) (*io::stream | error) = {
+fn dial_udp(addr: str, service: str) (io::file | error) = {
const result = resolve("udp", addr, service)?;
const addrs = result.0, port = result.1;
for (let i = 0z; i < len(addrs); i += 1) {
const addr = addrs[i];
match (udp::connect(addr, port)) {
- sock: udp::socket => return udp::stream(sock),
+ sock: io::file => return sock,
err: net::error => if (i + 1 >= len(addrs)) {
return err;
},
diff --git a/net/dial/registry.ha b/net/dial/registry.ha
@@ -26,7 +26,7 @@ export fn strerror(err: error) const str = {
};
// A dialer is a function which implements dial for a specific protocol.
-export type dialer = fn(addr: str, service: str) (*io::stream | error);
+export type dialer = fn(addr: str, service: str) (io::file | error);
type protocol = struct {
name: str,
diff --git a/net/dns/query.ha b/net/dns/query.ha
@@ -1,4 +1,5 @@
use errors;
+use io;
use net::ip;
use net::udp;
use time;
@@ -25,18 +26,18 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
];
};
- const socket4 = udp::listen(ip::ANY_V4, 0)?;
- defer udp::close(socket4);
- const socket6 = udp::listen(ip::ANY_V6, 0)?;
- defer udp::close(socket6);
+ let socket4 = udp::listen(ip::ANY_V4, 0)?;
+ defer io::close(&socket4);
+ let socket6 = udp::listen(ip::ANY_V6, 0)?;
+ defer io::close(&socket6);
const pollfd: [_]poll::pollfd = [
poll::pollfd {
- fd = udp::sockfd(socket4),
+ fd = io::fd(&socket4),
events = poll::event::POLLIN,
...
},
poll::pollfd {
- fd = udp::sockfd(socket6),
+ fd = io::fd(&socket6),
events = poll::event::POLLIN,
...
},
@@ -49,10 +50,10 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
// first one which sends us a reasonable answer.
for (let i = 0z; i < len(servers); i += 1) match (servers[i]) {
ip::addr4 => {
- udp::sendto(socket4, sendbuf[..z], servers[i], 53)?;
+ udp::sendto(&socket4, sendbuf[..z], servers[i], 53)?;
},
ip::addr6 => {
- udp::sendto(socket6, sendbuf[..z], servers[i], 53)?;
+ udp::sendto(&socket6, sendbuf[..z], servers[i], 53)?;
},
};
@@ -66,10 +67,10 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
let src: ip::addr = ip::ANY_V4;
if (pollfd[0].revents & poll::event::POLLIN != 0) {
- z = udp::recvfrom(socket4, recvbuf, &src, null)?;
+ z = udp::recvfrom(&socket4, recvbuf, &src, null)?;
};
if (pollfd[1].revents & poll::event::POLLIN != 0) {
- z = udp::recvfrom(socket6, recvbuf, &src, null)?;
+ z = udp::recvfrom(&socket6, recvbuf, &src, null)?;
};
let expected = false;
diff --git a/net/errors.ha b/net/errors.ha
@@ -25,6 +25,6 @@ export fn strerror(err: error) const str = {
// need to use this interface directly, preferring functions such as
// [[net::tcp::accept]].
export type listener = struct {
- accept: nullable *fn(l: *listener) (*io::stream | error),
+ accept: nullable *fn(l: *listener) (io::file | error),
shutdown: nullable *fn(l: *listener) void,
};
diff --git a/net/listener.ha b/net/listener.ha
@@ -3,9 +3,9 @@ use io;
// Accepts the next connection from a listener. Blocks until a new connection is
// available.
-export fn accept(l: *listener) (*io::stream | error) = {
+export fn accept(l: *listener) (io::file | error) = {
return match (l.accept) {
- f: *fn(l: *listener) (*io::stream | error) => f(l),
+ f: *fn(l: *listener) (io::file | error) => f(l),
null => errors::unsupported,
};
};
diff --git a/net/tcp/+linux.ha b/net/tcp/+linux.ha
@@ -11,7 +11,7 @@ export fn connect(
addr: ip::addr,
port: u16,
options: connect_option...
-) (*io::stream | net::error) = {
+) (io::file | net::error) = {
const sockaddr = ip::to_native(addr, port);
const sockfd = match (rt::socket(match (addr) {
ip::addr4 => rt::AF_INET: int,
@@ -32,8 +32,8 @@ export fn connect(
err: rt::errno => return errors::errno(err),
int => void,
};
- return alloc(os::fdopen(sockfd, ip::string(addr),
- io::mode::READ | io::mode::WRITE));
+ return io::fdopen(sockfd, ip::string(addr),
+ io::mode::READ | io::mode::WRITE);
};
// Binds a TCP listener to the given address.
@@ -99,11 +99,8 @@ export fn listen(
// Returns the remote address for a given connection, or void if none is
// available.
-export fn peeraddr(stream: *io::stream) ((ip::addr, u16) | void) = {
- let fd = match (os::streamfd(stream, true)) {
- fd: int => fd,
- void => return,
- };
+export fn peeraddr(peer: *io::file) ((ip::addr, u16) | void) = {
+ let fd = io::fd(peer);
let sn = rt::sockaddr {...};
let sz = size(rt::sockaddr): u32;
if (rt::getpeername(fd, &sn, &sz) is rt::errno) {
diff --git a/net/tcp/listener.ha b/net/tcp/listener.ha
@@ -3,7 +3,7 @@ use net;
// Accepts the next connection from a listener. Blocks until a new connection is
// available. This is a convenience wrapper around [[net::accept]].
-export fn accept(l: *net::listener) (*io::stream | net::error) = {
+export fn accept(l: *net::listener) (io::file | net::error) = {
return net::accept(l);
};
diff --git a/net/udp/+linux.ha b/net/udp/+linux.ha
@@ -5,13 +5,11 @@ use net;
use os;
use rt;
-export type socket = int;
-
// Creates a UDP socket and sets the default destination to the given address.
export fn connect(
dest: ip::addr,
port: u16,
-) (socket | net::error) = {
+) (io::file | net::error) = {
const sockfd = match (rt::socket(match (dest) {
ip::addr4 => rt::AF_INET: int,
ip::addr6 => rt::AF_INET6: int,
@@ -23,39 +21,19 @@ export fn connect(
const sockaddr = ip::to_native(dest, port);
const sz = size(rt::sockaddr): u32;
return match (rt::connect(sockfd, &sockaddr, sz)) {
- int => sockfd,
+ int => io::fdopen(sockfd,
+ "<udp connection>",
+ io::mode::READ | io::mode::WRITE),
err: rt::errno => errors::errno(err),
};
};
-// Gets the file descriptor associated with a UDP socket. This function is
-// non-portable.
-export fn sockfd(sock: socket) int = sock;
-
-// Creates an [[io::stream]] for an open UDP socket, which allows you to send
-// and receive UDP packets using [[io::read]] and [[io::write]], albiet without
-// being able to receive the sender address. Only meaningful if the socket was
-// created with [[connect]].
-export fn stream(sock: socket) *io::stream = {
- return alloc(os::fdopen(sock, "<UDP stream>",
- io::mode::READ | io::mode::WRITE));
-};
-
-// Obtains a [[socket]] for a given [[io::stream]], or returns void if it is not
-// a socket stream.
-export fn socket_for(stream: *io::stream) (socket | void) = {
- return match (os::streamfd(stream, false)) {
- fd: int => fd: socket,
- void => void,
- };
-};
-
// Creates a UDP socket bound to an interface.
export fn listen(
addr: ip::addr,
port: u16,
options: listen_option...
-) (socket | net::error) = {
+) (io::file | net::error) = {
const sockfd = match (rt::socket(match (addr) {
ip::addr4 => rt::AF_INET: int,
ip::addr6 => rt::AF_INET6: int,
@@ -85,17 +63,13 @@ export fn listen(
*options[i] = addr.1;
};
- return sockfd;
-};
-
-// Closes a UDP socket.
-export fn close(sock: socket) void = {
- rt::close(sock): void;
+ return io::fdopen(sockfd, "<udp listener>",
+ io::mode::READ | io::mode::WRITE);
};
// Sends a UDP packet to the destination previously specified by [[connect]].
-export fn send(sock: socket, buf: []u8) (size | net::error) = {
- return match (rt::send(sock, buf: *[*]u8, len(buf), 0)) {
+export fn send(sock: *io::file, buf: []u8) (size | net::error) = {
+ return match (rt::send(io::fd(sock), buf: *[*]u8, len(buf), 0)) {
sz: size => sz,
err: rt::errno => errors::errno(err),
};
@@ -103,14 +77,14 @@ export fn send(sock: socket, buf: []u8) (size | net::error) = {
// Sends a UDP packet using this socket.
export fn sendto(
- sock: socket,
+ sock: *io::file,
buf: []u8,
dest: ip::addr,
port: u16,
) (size | net::error) = {
const sockaddr = ip::to_native(dest, port);
const sz = size(rt::sockaddr): u32;
- return match (rt::sendto(sock, buf: *[*]u8, len(buf),
+ return match (rt::sendto(io::fd(sock), buf: *[*]u8, len(buf),
0, &sockaddr, sz)) {
sz: size => sz,
err: rt::errno => errors::errno(err),
@@ -119,14 +93,14 @@ export fn sendto(
// Receives a UDP packet from a bound socket.
export fn recvfrom(
- sock: socket,
+ sock: *io::file,
buf: []u8,
src: nullable *ip::addr,
port: nullable *u16,
) (size | net::error) = {
let addrsz = size(rt::sockaddr): u32;
const sockaddr = rt::sockaddr { ... };
- const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf),
+ const sz = match (rt::recvfrom(io::fd(sock), buf: *[*]u8, len(buf),
0, &sockaddr, &addrsz)) {
sz: size => sz,
err: rt::errno => return errors::errno(err),
diff --git a/net/unix/+linux.ha b/net/unix/+linux.ha
@@ -9,7 +9,7 @@ use types;
// Opens a UNIX socket connection to the path. Blocks until the connection is
// established.
-export fn connect(addr: addr) (*io::stream | net::error) = {
+export fn connect(addr: addr) (io::file | net::error) = {
let sockaddr = match (to_native(addr)) {
a: rt::sockaddr => a,
invalid => return errors::unsupported, // path too long
@@ -27,9 +27,9 @@ export fn connect(addr: addr) (*io::stream | net::error) = {
int => void,
};
static let buf: [rt::UNIX_PATH_MAX + 32]u8 = [0...];
- return alloc(os::fdopen(sockfd,
+ return io::fdopen(sockfd,
fmt::bsprintf(buf, "<unix connection {}>", addr),
- io::mode::READ | io::mode::WRITE));
+ io::mode::READ | io::mode::WRITE);
};
// Binds a UNIX socket listener to the given path.
diff --git a/net/unix/dial.ha b/net/unix/dial.ha
@@ -2,9 +2,9 @@ use io;
use net::dial;
use net;
-fn dial_unix(addr: str, service: str) (*io::stream | dial::error) = {
+fn dial_unix(addr: str, service: str) (io::file | dial::error) = {
return match (connect(addr)) {
- conn: *io::stream => conn,
+ conn: io::file => conn,
err: net::error => err,
};
};
diff --git a/net/unix/listener.ha b/net/unix/listener.ha
@@ -3,7 +3,7 @@ use net;
// Accepts the next connection from a listener. Blocks until a new connection is
// available. This is a convenience wrapper around [[net::accept]].
-export fn accept(l: *net::listener) (*io::stream | net::error) = {
+export fn accept(l: *net::listener) (io::file | net::error) = {
return net::accept(l);
};
diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha
@@ -1,122 +0,0 @@
-use errors;
-use io;
-use rt;
-
-export type fdstream = struct {
- io::stream,
- fd: int,
-};
-
-// Opens a Unix file descriptor as an io::stream.
-export fn fdopen(fd: int, name: str, mode: io::mode) fdstream = {
- let stream = fdstream {
- name = name,
- closer = &fd_close,
- copier = &fd_copy,
- seeker = &fd_seek,
- fd = fd,
- ...
- };
- if (mode & io::mode::READ == io::mode::READ) {
- stream.reader = &fd_read;
- };
- if (mode & io::mode::WRITE == io::mode::WRITE) {
- stream.writer = &fd_write;
- };
- return stream;
-};
-
-fn is_fdstream(s: *io::stream) bool = {
- return s.reader == &fd_read
- || s.writer == &fd_write
- || s.closer == &fd_close
- || s.copier == &fd_copy;
-};
-
-// Returns the file descriptor for a given [[io::stream]]. If there is no fd
-// associated with this stream, void is returned.
-//
-// If 'unwrap' is true, the stream will be unwrapped until an fdstream is found.
-// Note that many stream wrappers (such as [[io::tee]]) provide important
-// functionality, and using the file descriptor directly will circumvent that
-// functionality. Use with caution.
-export fn streamfd(s: *io::stream, unwrap: bool) (int | void) = {
- for (unwrap && !is_fdstream(s)) {
- s = match (io::source(s)) {
- errors::unsupported => return,
- s: *io::stream => s,
- };
- };
- if (!is_fdstream(s)) {
- return;
- };
- let stream = s: *fdstream;
- return stream.fd;
-};
-
-fn fd_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
- let stream = s: *fdstream;
- return match (rt::read(stream.fd, buf: *[*]u8, len(buf))) {
- err: rt::errno => errors::errno(err),
- n: size => switch (n) {
- 0 => io::EOF,
- * => n,
- },
- };
-};
-
-fn fd_write(s: *io::stream, buf: const []u8) (size | io::error) = {
- let stream = s: *fdstream;
- return match (rt::write(stream.fd, buf: *const [*]u8, len(buf))) {
- err: rt::errno => errors::errno(err),
- n: size => n,
- };
-};
-
-fn fd_close(s: *io::stream) void = {
- let stream = s: *fdstream;
- rt::close(stream.fd)!;
-};
-
-def SENDFILE_MAX: size = 2147479552z;
-
-fn fd_copy(to: *io::stream, from: *io::stream) (size | io::error) = {
- if (!is_fdstream(from)) {
- return errors::unsupported;
- };
-
- let to = to: *fdstream, from = from: *fdstream;
- let sum = 0z;
- for (true) {
- let n = match (rt::sendfile(to.fd, from.fd,
- null, SENDFILE_MAX)) {
- err: rt::errno => switch (err) {
- rt::EINVAL => {
- if (sum == 0) {
- return errors::unsupported;
- };
- return errors::errno(err);
- },
- * => return errors::errno(err),
- },
- n: size => switch (n) {
- 0 => return sum,
- * => n,
- },
- };
- sum += n;
- };
- return sum;
-};
-
-fn fd_seek(
- s: *io::stream,
- off: io::off,
- whence: io::whence,
-) (io::off | io::error) = {
- let stream = s: *fdstream;
- return match (rt::lseek(stream.fd, off: i64, whence: uint)) {
- err: rt::errno => errors::errno(err),
- n: i64 => n: io::off,
- };
-};
diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha
@@ -1,9 +1,9 @@
use bufio;
use io;
-let static_stdin_fd: io::file = fdstream { ... };
-let static_stdout_fd: io::file = fdstream { ... };
-let static_stderr_fd: io::file = fdstream { ... };
+let static_stdin_fd: io::file = io::file { ... };
+let static_stdout_fd: io::file = io::file { ... };
+let static_stderr_fd: io::file = io::file { ... };
let static_stdin_bufio: bufio::bufstream = bufio::bufstream { ... };
let static_stdout_bufio: bufio::bufstream = bufio::bufstream { ... };
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -666,7 +666,6 @@ os() {
'$(PLATFORM)/environ.ha' \
'$(PLATFORM)/exit.ha' \
'$(PLATFORM)/dirfdfs.ha' \
- '$(PLATFORM)/fdstream.ha' \
'$(PLATFORM)/stdfd.ha' \
'$(PLATFORM)/fs.ha' \
stdfd.ha \
diff --git a/stdlib.mk b/stdlib.mk
@@ -977,7 +977,6 @@ stdlib_os_srcs= \
$(STDLIB)/os/$(PLATFORM)/environ.ha \
$(STDLIB)/os/$(PLATFORM)/exit.ha \
$(STDLIB)/os/$(PLATFORM)/dirfdfs.ha \
- $(STDLIB)/os/$(PLATFORM)/fdstream.ha \
$(STDLIB)/os/$(PLATFORM)/stdfd.ha \
$(STDLIB)/os/$(PLATFORM)/fs.ha \
$(STDLIB)/os/stdfd.ha \
@@ -2213,7 +2212,6 @@ testlib_os_srcs= \
$(STDLIB)/os/$(PLATFORM)/environ.ha \
$(STDLIB)/os/$(PLATFORM)/exit.ha \
$(STDLIB)/os/$(PLATFORM)/dirfdfs.ha \
- $(STDLIB)/os/$(PLATFORM)/fdstream.ha \
$(STDLIB)/os/$(PLATFORM)/stdfd.ha \
$(STDLIB)/os/$(PLATFORM)/fs.ha \
$(STDLIB)/os/stdfd.ha \
diff --git a/unix/tty/+linux/isatty.ha b/unix/tty/+linux/isatty.ha
@@ -4,10 +4,7 @@ use os;
// Returns whether the given stream is connected to a terminal.
export fn isatty(stream: *io::stream) bool = {
- let fd = match (os::streamfd(stream, true)) {
- f: int => f,
- void => return false,
- };
+ let fd = io::fd(stream);
let wsz = rt::winsize { ... };
return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
e: rt::errno => false,
diff --git a/unix/tty/+linux/winsize.ha b/unix/tty/+linux/winsize.ha
@@ -5,10 +5,7 @@ use rt;
// Returns the dimensions of underlying terminal of the stream.
export fn winsize(tty: *io::stream) (ttysize | error) = {
- let fd = match (os::streamfd(tty, true)) {
- f: int => f,
- void => return errors::invalid,
- };
+ let fd = io::fd(tty);
let wsz = rt::winsize { ... };
return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
e: rt::errno => switch (e: int) {