commit 2f3b9aa82299f68037b6223b588f752e94ae8e8b
parent 40b07de56edb98d655097d8a82e76bfb8965d5c0
Author: Egor <egor@opensrc.club>
Date: Tue, 10 May 2022 20:03:52 +0300
net: add sockflags to connect/accept/socketpair
Signed-off-by: Egor <egor@opensrc.club>
Diffstat:
10 files changed, 176 insertions(+), 34 deletions(-)
diff --git a/net/tcp/+freebsd.ha b/net/tcp/+freebsd.ha
@@ -22,7 +22,16 @@ export fn connect(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -30,8 +39,11 @@ export fn connect(
};
for (let i = 0z; i < len(options); i += 1) {
- // The only option is keepalive right now
- setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ match (options[i]) {
+ case keepalive =>
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ case => void;
+ };
};
const sz = ip::native_addrlen(addr);
match (rt::connect(sockfd, &sockaddr, sz)) {
@@ -55,7 +67,16 @@ export fn listen(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -73,7 +94,7 @@ export fn listen(
setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
case let b: backlog =>
bk = b;
- case let p: portassignment => void;
+ case => void;
};
};
diff --git a/net/tcp/+linux.ha b/net/tcp/+linux.ha
@@ -22,7 +22,16 @@ export fn connect(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -30,8 +39,11 @@ export fn connect(
};
for (let i = 0z; i < len(options); i += 1) {
- // The only option is keepalive right now
- setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ match (options[i]) {
+ case keepalive =>
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ case => void;
+ };
};
const sz = size(rt::sockaddr): u32;
match (rt::connect(sockfd, &sockaddr, sz)) {
@@ -55,7 +67,16 @@ export fn listen(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -73,7 +94,7 @@ export fn listen(
setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
case let b: backlog =>
bk = b;
- case let p: portassignment => void;
+ case => void;
};
};
diff --git a/net/tcp/options.ha b/net/tcp/options.ha
@@ -1,5 +1,6 @@
// License: MPL-2.0
// (c) 2021 Drew DeVault <sir@cmpwn.com>
+use net;
// Enables keep-alive for a socket.
export type keepalive = void;
@@ -20,7 +21,7 @@ export type reuseaddr = void;
export type portassignment = *u16;
// Options for [[connect]].
-export type connect_option = keepalive;
+export type connect_option = (keepalive | net::sockflags);
// Options for [[listen]].
export type listen_option = (
@@ -28,4 +29,5 @@ export type listen_option = (
reuseport |
reuseaddr |
backlog |
- portassignment);
+ portassignment |
+ net::sockflags);
diff --git a/net/udp/+freebsd.ha b/net/udp/+freebsd.ha
@@ -12,6 +12,7 @@ use rt;
export fn connect(
dest: ip::addr,
port: u16,
+ options: connect_option...
) (io::file | net::error) = {
const family = match (dest) {
case ip::addr4 =>
@@ -19,7 +20,13 @@ export fn connect(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only sockflags for now
+ f |= options[i];
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -48,7 +55,16 @@ export fn listen(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -64,7 +80,12 @@ export fn listen(
};
for (let i = 0z; i < len(options); i += 1) {
- // The only option is portassignment right now
+ let portout = match (options[i]) {
+ case let p: portassignment =>
+ yield p;
+ case =>
+ continue;
+ };
let sn = rt::sockaddr {...};
let al = size(rt::sockaddr): u32;
match (rt::getsockname(sockfd, &sn, &al)) {
@@ -73,7 +94,7 @@ export fn listen(
case int => void;
};
const addr = ip::from_native(sn);
- *options[i] = addr.1;
+ *portout = addr.1;
};
return io::fdopen(sockfd);
diff --git a/net/udp/+linux.ha b/net/udp/+linux.ha
@@ -12,6 +12,7 @@ use rt;
export fn connect(
dest: ip::addr,
port: u16,
+ options: connect_option...
) (io::file | net::error) = {
const family = match (dest) {
case ip::addr4 =>
@@ -19,7 +20,13 @@ export fn connect(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only sockflags for now
+ f |= options[i];
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -48,7 +55,16 @@ export fn listen(
case ip::addr6 =>
yield rt::AF_INET6: int;
};
- const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -64,7 +80,12 @@ export fn listen(
};
for (let i = 0z; i < len(options); i += 1) {
- // The only option is portassignment right now
+ let portout = match (options[i]) {
+ case let p: portassignment =>
+ yield p;
+ case =>
+ continue;
+ };
let sn = rt::sockaddr {...};
let al = size(rt::sockaddr): u32;
match (rt::getsockname(sockfd, &sn, &al)) {
@@ -73,7 +94,7 @@ export fn listen(
case int => void;
};
const addr = ip::from_native(sn);
- *options[i] = addr.1;
+ *portout = addr.1;
};
return io::fdopen(sockfd);
diff --git a/net/udp/options.ha b/net/udp/options.ha
@@ -1,12 +1,16 @@
// License: MPL-2.0
// (c) 2021 Drew DeVault <sir@cmpwn.com>
+use net;
// To have the system select an arbitrary unused port for [[listen]], set port to
// zero. To retrieve the assigned port, provide this as one of the options and
// the addressed u16 will be filled in with the port.
export type portassignment = *u16;
+// Options for [[connect]].
+export type connect_option = net::sockflags;
+
// Options available for [[listen]].
-export type listen_option = portassignment;
+export type listen_option = (portassignment | net::sockflags);
// TODO: Add send/recv flags
diff --git a/net/unix/+freebsd.ha b/net/unix/+freebsd.ha
@@ -12,14 +12,23 @@ use types;
// Opens a UNIX socket connection to the path. Blocks until the connection is
// established.
-export fn connect(addr: addr) (io::file | net::error) = {
+export fn connect(
+ addr: addr,
+ options: connect_option...
+) (io::file | net::error) = {
let sockaddr = match (to_native(addr)) {
case let a: rt::sockaddr =>
yield a;
case invalid =>
return errors::unsupported; // path too long
};
- const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only sockflags for now
+ f |= options[i];
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -47,7 +56,16 @@ export fn listen(
case invalid =>
return errors::unsupported; // path too long
};
- const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -56,8 +74,11 @@ export fn listen(
let bk: u32 = 10;
for (let i = 0z; i < len(options); i += 1) {
- // Only option is backlog right now
- bk = options[i];
+ match (options[i]) {
+ case let b: backlog =>
+ bk = b;
+ case => void;
+ };
};
match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
diff --git a/net/unix/+linux.ha b/net/unix/+linux.ha
@@ -13,14 +13,23 @@ use types;
// Opens a UNIX socket connection to the path. Blocks until the connection is
// established.
-export fn connect(addr: addr) (io::file | net::error) = {
+export fn connect(
+ addr: addr,
+ options: connect_option...
+) (io::file | net::error) = {
let sockaddr = match (to_native(addr)) {
case let a: rt::sockaddr =>
yield a;
case invalid =>
return errors::unsupported; // path too long
};
- const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only sockflags for now
+ f |= options[i];
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -48,7 +57,16 @@ export fn listen(
case invalid =>
return errors::unsupported; // path too long
};
- const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | rt::SOCK_CLOEXEC, 0)) {
+ let f = 0i;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case let fl: net::sockflags =>
+ f |= fl;
+ case => void;
+ };
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
case let err: rt::errno =>
return errors::errno(err);
case let fd: int =>
@@ -57,8 +75,11 @@ export fn listen(
let bk: u32 = 10;
for (let i = 0z; i < len(options); i += 1) {
- // Only option is backlog right now
- bk = options[i];
+ match (options[i]) {
+ case let b: backlog =>
+ bk = b;
+ case => void;
+ };
};
match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
diff --git a/net/unix/options.ha b/net/unix/options.ha
@@ -1,9 +1,13 @@
// License: MPL-2.0
// (c) 2021 Drew DeVault <sir@cmpwn.com>
+use net;
// Configures the backlog size for a listener. If not specified, a sensible
// default (10) is used.
export type backlog = u32;
+// Options for [[connect]].
+export type connect_option = net::sockflags;
+
// Options for [[listen]].
-export type listen_option = backlog;
+export type listen_option = (backlog | net::sockflags);
diff --git a/net/unix/socketpair.ha b/net/unix/socketpair.ha
@@ -9,9 +9,15 @@ use io;
// A thin wrapper around socketpair(2) that presumes [[rt::AF_UNIX]] for the
// domain and returns an unnamed pair of sockets of type [[rt::SOCK_STREAM]].
-export fn socketpair() ((io::file, io::file) | net::error) = {
+export fn socketpair(flags: net::sockflags...) ((io::file, io::file) | net::error) = {
let sv: [2]int = [0...];
- match (rt::socketpair(rt::AF_UNIX : int, (rt::SOCK_STREAM | rt::SOCK_CLOEXEC) : int, 0, &sv)) {
+ // Apply any supplied flags
+ let f = 0i;
+ for (let i = 0z; i < len(flags); i += 1) {
+ f |= flags[i];
+ };
+ f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
+ match (rt::socketpair(rt::AF_UNIX : int, (rt::SOCK_STREAM | f) : int, 0, &sv)) {
case let err: rt::errno =>
return errors::errno(err);
case =>