commit 6a749628f21d3fade9a681919550a16c6274a0d7
parent 41744ce653238bcc8e4db96133efa728b00a9605
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 19 Jun 2021 13:19:10 -0400
net::udp: new module
Also simplifes and streamlines net+linux overall.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
11 files changed, 347 insertions(+), 145 deletions(-)
diff --git a/net/+linux.ha b/net/+linux.ha
@@ -1,3 +1,4 @@
+// Some common code for handling sockets on +linux
use errors;
use fmt;
use io;
@@ -6,19 +7,6 @@ use os;
use rt;
use strings;
-export fn connect_fd(
- addr: rt::sockaddr,
- options: connect_option...
-) (int | io::error) = {
- const sockfd = mksockfd(addr)?;
- for (let i = 0z; i < len(options); i += 1) {
- // The only option is keepalive right now
- setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
- };
- wrap(rt::connect(sockfd, &addr, sockasz(addr)))?;
- return sockfd;
-};
-
export type stream_listener = struct {
l: listener,
fd: int,
@@ -31,53 +19,15 @@ export fn listenerfd(l: *listener) (int | void) = {
};
};
-export fn listen_fd(
- addr: rt::sockaddr,
- options: listen_option...
-) (int | io::error) = {
- const sockfd = mksockfd(addr)?;
-
- let bk: u32 = 10;
- let portout: nullable *u16 = null;
-
- for (let i = 0z; i < len(options); i += 1) {
- match (options[i]) {
- reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?,
- reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?,
- keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?,
- b: backlog => bk = b,
- p: portassignment => portout = p,
- };
- };
- setfcntl(sockfd, rt::O_CLOEXEC)!;
-
- wrap(rt::bind(sockfd, &addr, sockasz(addr)))?;
- wrap(rt::listen(sockfd, bk))?;
-
- match (portout) {
- p: *u16 => {
- if (addr.in.sin_family != rt::AF_INET &&
- addr.in.sin_family != rt::AF_INET6) {
- return errors::unsupported;
- };
- let sn = rt::sockaddr {...};
- let al = sockasz(addr);
- wrap(rt::getsockname(sockfd, &sn, &al))?;
- const addr = ip::from_native(sn);
- *p = addr.1;
- },
- null => void,
- };
-
- return sockfd;
-};
-
export fn stream_accept(l: *listener) (*io::stream | io::error) = {
assert(l.accept == &stream_accept);
let l = l: *stream_listener;
let sn = rt::sockaddr {...};
const sz = size(rt::sockaddr): u32;
- const fd = wrap(rt::accept(l.fd, &sn, &sz))?;
+ const fd = match (rt::accept(l.fd, &sn, &sz)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
static let namebuf: [32]u8 = [0...];
return os::fdopen(fd, fmt::bsprintf(namebuf, "<net connection {}>", fd),
@@ -90,36 +40,3 @@ export fn stream_shutdown(l: *listener) void = {
rt::close(l.fd)!;
free(l);
};
-
-fn setsockopt(sockfd: int, option: int, value: bool) (void | rt::errno) = {
- let val: int = if (value) 1 else 0;
- rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
- &val: *void, size(int): u32)?;
- return;
-};
-
-fn setfcntl(sockfd: int, flag: int) (void | rt::errno) = {
- let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)?;
- rt::fcntl(sockfd, rt::F_SETFL, flags | flag)!;
- return;
-};
-
-fn wrap(ie: (int | rt::errno)) (int | io::error) = {
- match (ie) {
- i: int => i,
- err: rt::errno => errors::errno(err),
- };
-};
-
-fn sockasz(addr: rt::sockaddr) u32 = {
- return switch (addr.in.sin_family) {
- rt::AF_INET => size(rt::sockaddr_in): u32,
- rt::AF_INET6 => size(rt::sockaddr_in6): u32,
- rt::AF_UNIX => size(rt::sockaddr_un): u32,
- * => size(rt::sockaddr): u32,
- };
-};
-
-export fn mksockfd(addr: rt::sockaddr) (int | io::error) = {
- return wrap(rt::socket(addr.in.sin_family: int, rt::SOCK_STREAM, 0))?;
-};
diff --git a/net/options.ha b/net/options.ha
@@ -1,30 +0,0 @@
-// Enables keep-alive for a socket.
-export type keepalive = void;
-
-// Configures the backlog size for a listener. If not specified, a sensible
-// default (10) is used.
-export type backlog = u32;
-
-// Enables port re-use for a TCP listener.
-export type reuseport = void;
-
-// Enables address re-use for a TCP listener.
-export type reuseaddr = void;
-
-// 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]]. Not all options are supported by all socket types or
-// platforms.
-export type connect_option = keepalive;
-
-// Options for [[listen]]. Not all options are supported by all socket types or
-// platforms.
-export type listen_option = (
- keepalive |
- reuseport |
- reuseaddr |
- backlog |
- portassignment);
diff --git a/net/tcp/+linux.ha b/net/tcp/+linux.ha
@@ -1,3 +1,4 @@
+use errors;
use io;
use net::ip;
use net;
@@ -9,10 +10,28 @@ use rt;
export fn connect(
addr: ip::addr,
port: u16,
- options: net::connect_option...
+ options: connect_option...
) (*io::stream | io::error) = {
const sockaddr = ip::to_native(addr, port);
- const sockfd = net::connect_fd(sockaddr, options...)?;
+ const sockfd = match (rt::socket(match (addr) {
+ ip::addr4 => rt::AF_INET: int,
+ ip::addr6 => rt::AF_INET6: int,
+ }, rt::SOCK_STREAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ for (let i = 0z; i < len(options); i += 1) {
+ // The only option is keepalive right now
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ };
+ const sz = size(rt::sockaddr): u32;
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
return os::fdopen(sockfd, ip::string(addr),
io::mode::READ | io::mode::WRITE);
};
@@ -21,10 +40,54 @@ export fn connect(
export fn listen(
addr: ip::addr,
port: u16,
- options: net::listen_option...
+ options: listen_option...
) (*net::listener | io::error) = {
- let sockaddr = ip::to_native(addr, port);
- let sockfd = net::listen_fd(sockaddr, options...)?;
+ const sockaddr = ip::to_native(addr, port);
+ const sockfd = match (rt::socket(match (addr) {
+ ip::addr4 => rt::AF_INET: int,
+ ip::addr6 => rt::AF_INET6: int,
+ }, rt::SOCK_STREAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ let bk: u32 = 10;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?,
+ reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?,
+ keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?,
+ b: backlog => bk = b,
+ p: portassignment => void,
+ };
+ };
+
+ match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr): u32)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+ match ((rt::listen(sockfd, bk))) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+
+ for (let i = 0z; i < len(options); i += 1) {
+ let portout = match (options[i]) {
+ p: portassignment => p,
+ * => continue,
+ };
+ let sn = rt::sockaddr {...};
+ let al = size(rt::sockaddr): u32;
+ match (rt::getsockname(sockfd, &sn, &al)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+ const addr = ip::from_native(sn);
+ *portout = addr.1;
+ };
+
return alloc(net::stream_listener {
l = net::listener {
accept = &net::stream_accept,
@@ -48,3 +111,16 @@ export fn peeraddr(stream: *io::stream) ((ip::addr, u16) | void) = {
};
return ip::from_native(sn);
};
+
+fn setsockopt(
+ sockfd: int,
+ option: int,
+ value: bool,
+) (void | errors::opaque) = {
+ let val: int = if (value) 1 else 0;
+ return match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
+ &val: *void, size(int): u32)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
diff --git a/net/tcp/options.ha b/net/tcp/options.ha
@@ -0,0 +1,28 @@
+// Enables keep-alive for a socket.
+export type keepalive = void;
+
+// Configures the backlog size for a listener. If not specified, a sensible
+// default (10) is used.
+export type backlog = u32;
+
+// Enables port re-use for a TCP listener.
+export type reuseport = void;
+
+// Enables address re-use for a TCP listener.
+export type reuseaddr = void;
+
+// 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 = keepalive;
+
+// Options for [[listen]].
+export type listen_option = (
+ keepalive |
+ reuseport |
+ reuseaddr |
+ backlog |
+ portassignment);
diff --git a/net/udp/+linux.ha b/net/udp/+linux.ha
@@ -0,0 +1,123 @@
+use errors;
+use net;
+use net::ip;
+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 | errors::opaque) = {
+ const sockfd = match (rt::socket(match (dest) {
+ ip::addr4 => rt::AF_INET: int,
+ ip::addr6 => rt::AF_INET6: int,
+ }, rt::SOCK_DGRAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+
+ const sockaddr = ip::to_native(dest, port);
+ const sz = size(rt::sockaddr): u32;
+ return match (rt::connect(sockfd, &sockaddr, sz)) {
+ int => sockfd,
+ err: rt::errno => errors::errno(err),
+ };
+};
+
+// Creates a UDP socket bound to an interface.
+export fn listen(
+ addr: ip::addr,
+ port: u16,
+ options: bind_option...
+) (socket | errors::opaque) = {
+ const sockfd = match (rt::socket(match (addr) {
+ ip::addr4 => rt::AF_INET: int,
+ ip::addr6 => rt::AF_INET6: int,
+ }, rt::SOCK_DGRAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ const sockaddr = ip::to_native(addr, port);
+ const sz = size(rt::sockaddr): u32;
+ match (rt::bind(sockfd, &sockaddr, sz)) {
+ int => void,
+ err: rt::errno => return errors::errno(err),
+ };
+
+ for (let i = 0z; i < len(options); i += 1) {
+ // The only option is portassignment right now
+ let sn = rt::sockaddr {...};
+ let al = size(rt::sockaddr): u32;
+ match (rt::getsockname(sockfd, &sn, &al)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+ const addr = ip::from_native(sn);
+ *options[i] = addr.1;
+ };
+
+ return sockfd;
+};
+
+// Closes a UDP socket.
+export fn close(sock: socket) void = {
+ rt::close(sock): void;
+};
+
+// Sends a UDP packet to the destination previously specified by [[connect]].
+export fn send(sock: socket, buf: []u8) (size | errors::opaque) = {
+ return match (rt::send(sock, buf: *[*]u8, len(buf), 0)) {
+ sz: size => sz,
+ err: rt::errno => errors::errno(err),
+ };
+};
+
+// Sends a UDP packet using this socket.
+export fn sendto(
+ sock: socket,
+ buf: []u8,
+ dest: ip::addr,
+ port: u16,
+) (size | errors::opaque) = {
+ const sockaddr = ip::to_native(dest, port);
+ const sz = size(rt::sockaddr): u32;
+ return match (rt::sendto(sock, buf: *[*]u8, len(buf),
+ 0, &sockaddr, sz)) {
+ sz: size => sz,
+ err: rt::errno => errors::errno(err),
+ };
+};
+
+// Receives a UDP packet from a bound socket.
+export fn recvfrom(
+ sock: socket,
+ buf: []u8,
+ src: nullable *ip::addr,
+ port: nullable *u16,
+) (size | errors::opaque) = {
+ let addrsz = size(rt::sockaddr): u32;
+ const sockaddr = rt::sockaddr { ... };
+ const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf),
+ 0, &sockaddr, &addrsz)) {
+ sz: size => sz,
+ err: rt::errno => errors::errno(err),
+ };
+
+ assert(addrsz <= size(rt::sockaddr));
+ const peer = ip::from_native(sockaddr);
+ match (src) {
+ null => void,
+ src: *ip::addr => *src = peer.0,
+ };
+ match (port) {
+ null => void,
+ port: *u16 => *port = peer.1,
+ };
+
+ return sz;
+};
diff --git a/net/udp/options.ha b/net/udp/options.ha
@@ -0,0 +1,9 @@
+// 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 available for [[bind]].
+export type bind_option = portassignment;
+
+// TODO: Add send/recv flags
diff --git a/net/unix/+linux.ha b/net/unix/+linux.ha
@@ -7,33 +7,62 @@ use rt;
use strings;
use types;
-// Opens a UNIX socket connection to the path. Blocks until the
-// connection is established.
-export fn connect(
- addr: addr,
- options: net::connect_option...
-) (*io::stream | io::error) = {
+// Opens a UNIX socket connection to the path. Blocks until the connection is
+// established.
+export fn connect(addr: addr) (*io::stream | io::error) = {
let sockaddr = match (to_native(addr)) {
a: rt::sockaddr => a,
invalid => return errors::unsupported, // path too long
};
- const sockfd = net::connect_fd(sockaddr, options...)?;
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ const sz = size(rt::sockaddr): u32;
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
static let buf: [rt::UNIX_PATH_MAX + 32]u8 = [0...];
return os::fdopen(sockfd,
fmt::bsprintf(buf, "<unix connection {}>", addr),
io::mode::READ | io::mode::WRITE);
};
-// Binds a UNIX socket listener at the given path.
+// Binds a UNIX socket listener to the given path.
export fn listen(
addr: addr,
- options: net::listen_option...
+ options: listen_option...
) (*net::listener | io::error) = {
let sockaddr = match (to_native(addr)) {
a: rt::sockaddr => a,
invalid => return errors::unsupported, // path too long
};
- let sockfd = net::listen_fd(sockaddr, options...)?;
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
+ err: rt::errno => return errors::errno(err),
+ fd: int => fd,
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ let bk: u32 = 10;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only option is backlog right now
+ bk = options[i];
+ };
+
+ match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr): u32)) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+ match ((rt::listen(sockfd, bk))) {
+ err: rt::errno => return errors::errno(err),
+ int => void,
+ };
+
return alloc(net::stream_listener {
l = net::listener {
accept = &net::stream_accept,
diff --git a/net/unix/options.ha b/net/unix/options.ha
@@ -0,0 +1,6 @@
+// Configures the backlog size for a listener. If not specified, a sensible
+// default (10) is used.
+export type backlog = u32;
+
+// Options for [[listen]].
+export type listen_option = backlog;
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -496,11 +496,11 @@ export fn recvfrom(sockfd: int, buf: *void, len_: size, flags: int,
};
export fn sendto(sockfd: int, buf: *void, len_: size, flags: int,
- dest_addr: nullable *sockaddr, addrlen: nullable *u32
+ dest_addr: nullable *sockaddr, addrlen: u32
) (size | errno) = {
return wrap_return(syscall6(SYS_sendto,
sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
- dest_addr: uintptr: u64, addrlen: uintptr: u64))?: size;
+ dest_addr: uintptr: u64, addrlen: u64))?: size;
};
export fn recv(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
@@ -508,7 +508,7 @@ export fn recv(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) =
};
export fn send(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
- return sendto(sockfd, buf, len_, flags, null, null);
+ return sendto(sockfd, buf, len_, flags, null, 0);
};
export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *void, optlen: nullable *u32) (int | errno) = {
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -545,7 +545,6 @@ net() {
printf '# net\n'
gen_srcs net \
'$(PLATFORM).ha' \
- options.ha \
listener.ha
gen_ssa net io os strings net::ip errors rt fmt
}
@@ -571,15 +570,25 @@ net_ip() {
net_tcp() {
printf '# net::tcp\n'
gen_srcs net::tcp \
- '$(PLATFORM).ha'
+ '$(PLATFORM).ha' \
+ options.ha
gen_ssa net::tcp io net net::ip os rt
}
+net_udp() {
+ printf '# net::udp\n'
+ gen_srcs net::udp \
+ '$(PLATFORM).ha' \
+ options.ha
+ gen_ssa net::udp net net::ip errors rt
+}
+
net_unix() {
printf '# net::unix\n'
gen_srcs net::unix \
+ '$(PLATFORM).ha' \
addr.ha \
- '$(PLATFORM).ha'
+ options.ha
gen_ssa net::unix net errors os io strings types fmt
}
@@ -801,6 +810,7 @@ linux::vdso
net
net::ip
net::tcp
+net::udp
net::unix
math::random
os
diff --git a/stdlib.mk b/stdlib.mk
@@ -253,6 +253,10 @@ hare_stdlib_deps+=$(stdlib_net_ip)
stdlib_net_tcp=$(HARECACHE)/net/tcp/net_tcp.o
hare_stdlib_deps+=$(stdlib_net_tcp)
+# gen_lib net::udp
+stdlib_net_udp=$(HARECACHE)/net/udp/net_udp.o
+hare_stdlib_deps+=$(stdlib_net_udp)
+
# gen_lib net::unix
stdlib_net_unix=$(HARECACHE)/net/unix/net_unix.o
hare_stdlib_deps+=$(stdlib_net_unix)
@@ -803,7 +807,6 @@ $(HARECACHE)/linux/vdso/linux_vdso.ssa: $(stdlib_linux_vdso_srcs) $(stdlib_rt) $
# net
stdlib_net_srcs= \
$(STDLIB)/net/$(PLATFORM).ha \
- $(STDLIB)/net/options.ha \
$(STDLIB)/net/listener.ha
$(HARECACHE)/net/net.ssa: $(stdlib_net_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_os) $(stdlib_strings) $(stdlib_net_ip) $(stdlib_errors) $(stdlib_rt) $(stdlib_fmt)
@@ -826,7 +829,8 @@ $(HARECACHE)/net/ip/net_ip.ssa: $(stdlib_net_ip_srcs) $(stdlib_rt) $(stdlib_byte
# net::tcp
# net::tcp
stdlib_net_tcp_srcs= \
- $(STDLIB)/net/tcp/$(PLATFORM).ha
+ $(STDLIB)/net/tcp/$(PLATFORM).ha \
+ $(STDLIB)/net/tcp/options.ha
$(HARECACHE)/net/tcp/net_tcp.ssa: $(stdlib_net_tcp_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_net) $(stdlib_net_ip) $(stdlib_os) $(stdlib_rt)
@printf 'HAREC \t$@\n'
@@ -834,11 +838,24 @@ $(HARECACHE)/net/tcp/net_tcp.ssa: $(stdlib_net_tcp_srcs) $(stdlib_rt) $(stdlib_i
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::tcp \
-t$(HARECACHE)/net/tcp/net_tcp.td $(stdlib_net_tcp_srcs)
+# net::udp
+# net::udp
+stdlib_net_udp_srcs= \
+ $(STDLIB)/net/udp/$(PLATFORM).ha \
+ $(STDLIB)/net/udp/options.ha
+
+$(HARECACHE)/net/udp/net_udp.ssa: $(stdlib_net_udp_srcs) $(stdlib_rt) $(stdlib_net) $(stdlib_net_ip) $(stdlib_errors) $(stdlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net/udp
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::udp \
+ -t$(HARECACHE)/net/udp/net_udp.td $(stdlib_net_udp_srcs)
+
# net::unix
# net::unix
stdlib_net_unix_srcs= \
+ $(STDLIB)/net/unix/$(PLATFORM).ha \
$(STDLIB)/net/unix/addr.ha \
- $(STDLIB)/net/unix/$(PLATFORM).ha
+ $(STDLIB)/net/unix/options.ha
$(HARECACHE)/net/unix/net_unix.ssa: $(stdlib_net_unix_srcs) $(stdlib_rt) $(stdlib_net) $(stdlib_errors) $(stdlib_os) $(stdlib_io) $(stdlib_strings) $(stdlib_types) $(stdlib_fmt)
@printf 'HAREC \t$@\n'
@@ -1318,6 +1335,10 @@ hare_testlib_deps+=$(testlib_net_ip)
testlib_net_tcp=$(TESTCACHE)/net/tcp/net_tcp.o
hare_testlib_deps+=$(testlib_net_tcp)
+# gen_lib net::udp
+testlib_net_udp=$(TESTCACHE)/net/udp/net_udp.o
+hare_testlib_deps+=$(testlib_net_udp)
+
# gen_lib net::unix
testlib_net_unix=$(TESTCACHE)/net/unix/net_unix.o
hare_testlib_deps+=$(testlib_net_unix)
@@ -1888,7 +1909,6 @@ $(TESTCACHE)/linux/vdso/linux_vdso.ssa: $(testlib_linux_vdso_srcs) $(testlib_rt)
# net
testlib_net_srcs= \
$(STDLIB)/net/$(PLATFORM).ha \
- $(STDLIB)/net/options.ha \
$(STDLIB)/net/listener.ha
$(TESTCACHE)/net/net.ssa: $(testlib_net_srcs) $(testlib_rt) $(testlib_io) $(testlib_os) $(testlib_strings) $(testlib_net_ip) $(testlib_errors) $(testlib_rt) $(testlib_fmt)
@@ -1912,7 +1932,8 @@ $(TESTCACHE)/net/ip/net_ip.ssa: $(testlib_net_ip_srcs) $(testlib_rt) $(testlib_b
# net::tcp
# net::tcp
testlib_net_tcp_srcs= \
- $(STDLIB)/net/tcp/$(PLATFORM).ha
+ $(STDLIB)/net/tcp/$(PLATFORM).ha \
+ $(STDLIB)/net/tcp/options.ha
$(TESTCACHE)/net/tcp/net_tcp.ssa: $(testlib_net_tcp_srcs) $(testlib_rt) $(testlib_io) $(testlib_net) $(testlib_net_ip) $(testlib_os) $(testlib_rt)
@printf 'HAREC \t$@\n'
@@ -1920,11 +1941,24 @@ $(TESTCACHE)/net/tcp/net_tcp.ssa: $(testlib_net_tcp_srcs) $(testlib_rt) $(testli
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::tcp \
-t$(TESTCACHE)/net/tcp/net_tcp.td $(testlib_net_tcp_srcs)
+# net::udp
+# net::udp
+testlib_net_udp_srcs= \
+ $(STDLIB)/net/udp/$(PLATFORM).ha \
+ $(STDLIB)/net/udp/options.ha
+
+$(TESTCACHE)/net/udp/net_udp.ssa: $(testlib_net_udp_srcs) $(testlib_rt) $(testlib_net) $(testlib_net_ip) $(testlib_errors) $(testlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net/udp
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::udp \
+ -t$(TESTCACHE)/net/udp/net_udp.td $(testlib_net_udp_srcs)
+
# net::unix
# net::unix
testlib_net_unix_srcs= \
+ $(STDLIB)/net/unix/$(PLATFORM).ha \
$(STDLIB)/net/unix/addr.ha \
- $(STDLIB)/net/unix/$(PLATFORM).ha
+ $(STDLIB)/net/unix/options.ha
$(TESTCACHE)/net/unix/net_unix.ssa: $(testlib_net_unix_srcs) $(testlib_rt) $(testlib_net) $(testlib_errors) $(testlib_os) $(testlib_io) $(testlib_strings) $(testlib_types) $(testlib_fmt)
@printf 'HAREC \t$@\n'