commit 0b68a9ec9421a9319e3adc57b1f35858d172156a
parent bc5ba82fe0e58d44cf89ffff81b3bf1b8795bb4a
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 19 Jun 2021 10:37:20 -0400
net: reorganize modules
This moves each protocol's connect/listen functions into their
respective modules, e.g. net::tcp and net::unix. This allows us to add
new protocols without updating net.
Future work will include:
- SOCK_DGRAM abstraction for net
- SOCK_DGRAM providers for net::udp and net::ip
- Out of tree implementations of net::bluetooth et al
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
10 files changed, 326 insertions(+), 333 deletions(-)
diff --git a/net/+linux.ha b/net/+linux.ha
@@ -0,0 +1,125 @@
+use errors;
+use fmt;
+use io;
+use net::ip;
+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,
+};
+
+// Gets the fd of the listener's socket. This function is not portable.
+export fn listenerfd(l: *listener) (int | void) = {
+ if (l.accept == &stream_accept) {
+ return (l: *stream_listener).fd;
+ };
+};
+
+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))?;
+
+ static let namebuf: [32]u8 = [0...];
+ return os::fdopen(fd, fmt::bsprintf(namebuf, "<net connection {}>", fd),
+ io::mode::READ | io::mode::WRITE);
+};
+
+export fn stream_shutdown(l: *listener) void = {
+ assert(l.shutdown == &stream_shutdown);
+ let l = l: *stream_listener;
+ 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/+linux/socket.ha b/net/+linux/socket.ha
@@ -1,148 +0,0 @@
-use errors;
-use io;
-use net::ip;
-use net::unix;
-use os;
-use rt;
-use strings;
-
-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;
-};
-
-// Opens a TCP connection to the given host and port. Blocks until the
-// connection is established.
-export fn connect(
- addr: ip::addr,
- port: u16,
- options: connect_option...
-) (*io::stream | io::error) = {
- const sockaddr = ip::to_native(addr, port);
- const sockfd = connect_fd(sockaddr, options...)?;
- return os::fdopen(sockfd, string(addr),
- io::mode::READ | io::mode::WRITE);
-};
-
-// Opens a UNIX socket connection to the path. Blocks until the
-// connection is established.
-export fn connect_unix(
- addr: unix::addr,
- options: connect_option...
-) (*io::stream | io::error) = {
- let sockaddr = match (unix::to_native(addr)) {
- a: rt::sockaddr => a,
- unix::invalid => return errors::unsupported, // path too long
- };
- const sockfd = connect_fd(sockaddr, options...)?;
- return os::fdopen(sockfd, string(addr),
- io::mode::READ | io::mode::WRITE);
-};
-
-type stream_listener = struct {
- l: listener,
- fd: int,
-};
-
-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;
-};
-
-// Binds a TCP listener to the given address.
-export fn listen(
- addr: ip::addr,
- port: u16,
- options: listen_option...
-) (*listener | io::error) = {
- let sockaddr = ip::to_native(addr, port);
- let sockfd = listen_fd(sockaddr, options...)?;
- return alloc(stream_listener {
- l = listener {
- accept = &stream_accept,
- shutdown = &stream_shutdown,
- },
- fd = sockfd,
- }): *listener;
-};
-
-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 addr = from_native(sn);
- return os::fdopen(fd, string(addr),
- io::mode::READ | io::mode::WRITE);
-};
-
-fn stream_shutdown(l: *listener) void = {
- assert(l.shutdown == &stream_shutdown);
- let l = l: *stream_listener;
- rt::close(l.fd)!;
- free(l);
-};
-
-// Binds a UNIX socket listener at the given path.
-export fn listen_unix(
- addr: unix::addr,
- options: listen_option...
-) (*listener | io::error) = {
- let sockaddr = match (unix::to_native(addr)) {
- a: rt::sockaddr => a,
- unix::invalid => return errors::unsupported, // path too long
- };
- let sockfd = listen_fd(sockaddr, options...)?;
- return alloc(stream_listener {
- l = listener {
- accept = &stream_accept,
- shutdown = &stream_shutdown,
- },
- fd = sockfd,
- }): *listener;
-};
diff --git a/net/+linux/util.ha b/net/+linux/util.ha
@@ -1,78 +0,0 @@
-use errors;
-use io;
-use fmt;
-use net::ip;
-use net::unix;
-use os;
-use rt;
-
-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 mksockfd(addr: rt::sockaddr) (int | io::error) = {
- return wrap(rt::socket(addr.in.sin_family: int, rt::SOCK_STREAM, 0))?;
-};
-
-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,
- };
-};
-
-fn string(addr: (ip::addr | unix::addr)) str = {
- return match (addr) {
- ip: ip::addr => ip::string(ip),
- un: unix::addr => un,
- };
-};
-
-fn from_native(addr: rt::sockaddr) (ip::addr | unix::addr) = {
- return switch (addr.in.sin_family) {
- rt::AF_INET => ip::from_native(addr).0,
- rt::AF_INET6 => ip::from_native(addr).0,
- rt::AF_UNIX => unix::from_native(addr),
- * => abort("Wrong address family"),
- };
-};
-
-// 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,
- };
- let sn = rt::sockaddr {...};
- let sz = size(rt::sockaddr): u32;
- if (rt::getpeername(fd, &sn, &sz) is rt::errno) {
- return;
- };
- return ip::from_native(sn);
-};
-
-// Gets the fd of the listener's socket.
-export fn listenerfd(l: *listener) (int | void) = {
- if (l.accept == &stream_accept) {
- return (l: *stream_listener).fd;
- };
-};
diff --git a/net/listener.ha b/net/listener.ha
@@ -0,0 +1,26 @@
+use errors;
+use io;
+
+// A listener binds a socket and listens for incoming traffic for some
+// unspecified protocol.
+export type listener = struct {
+ accept: nullable *fn(l: *listener) (*io::stream | io::error),
+ shutdown: nullable *fn(l: *listener) void,
+};
+
+// Accepts the next connection from a listener. Blocks until a new connection is
+// available.
+export fn accept(l: *listener) (*io::stream | io::error) = {
+ return match (l.accept) {
+ f: *fn(l: *listener) (*io::stream | io::error) => f(l),
+ null => errors::unsupported,
+ };
+};
+
+// Shuts down a [[listener]] and frees resources associated with it.
+export fn shutdown(l: *listener) void = {
+ match (l.shutdown) {
+ f: *fn(l: *listener) void => f(l),
+ null => void,
+ };
+};
diff --git a/net/options.ha b/net/options.ha
@@ -0,0 +1,30 @@
+// 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/socket.ha b/net/socket.ha
@@ -1,92 +0,0 @@
-use errors;
-use io;
-use net::ip;
-
-// Enables keep-alive for a socket.
-export type keepalive = void;
-
-// Enables port re-use for a TCP listener.
-export type reuseport = void;
-
-// Enables address re-use for a TCP listener.
-export type reuseaddr = void;
-
-// Configures the backlog size for a listener. If not specified, a sensible
-// default (10) is used.
-export type backlog = u32;
-
-// 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 the [[listen]] family of functions.
-export type listen_option = (
- keepalive |
- reuseport |
- reuseaddr |
- backlog |
- portassignment);
-
-// Options for the [[connect]] family of functions.
-export type connect_option = keepalive;
-
-// Indicates that a send or recv operation should include out-of-band data.
-export type oob = []u8;
-
-// Options for [[send]] and [[recv]].
-export type dgram_option = oob;
-
-// A listener binds a socket and listens for incoming traffic for some
-// unspecified protocol.
-export type listener = struct {
- accept: nullable *fn(l: *listener) (*io::stream | io::error),
- send: nullable *fn(l: *listener, to: ip::addr, port: u16,
- buf: []u8, options: dgram_option...) (size | io::error),
- recv: nullable *fn(l: *listener,
- from: nullable *ip::addr, port: nullable *u16,
- buf: []u8, options: dgram_option...) (size | io::error),
- shutdown: nullable *fn(l: *listener) void,
-};
-
-// Accepts the next connection from a listener. Blocks until a new connection is
-// available.
-export fn accept(l: *listener) (*io::stream | io::error) = {
- return match (l.accept) {
- f: *fn(l: *listener) (*io::stream | io::error) => f(l),
- null => errors::unsupported,
- };
-};
-
-// Shuts down a [[listener]] and frees resources associated with it.
-export fn shutdown(l: *listener) void = {
- match (l.shutdown) {
- f: *fn(l: *listener) void => f(l),
- null => void,
- };
-};
-
-// Sends a datagram to the given destination, returning the number of bytes sent
-// (or an error).
-export fn send(
- l: *listener,
- to: ip::addr,
- port: u16,
- buf: []u8,
- options: dgram_option...
-) (size | io::error) = {
- abort(); // TODO
-};
-
-// Blocks until a datagram is received from a listener, writing it to the
-// provided buffer and returning the number of bytes received. Populates the
-// sender address and port in 'from' and 'port' if non-null.
-export fn recv(
- l: *listener,
- from: nullable *ip::addr,
- port: nullable *u16,
- buf: []u8,
- options: dgram_option...
-) (size | io::error) = {
- abort(); // TODO
-};
diff --git a/net/tcp/+linux.ha b/net/tcp/+linux.ha
@@ -0,0 +1,50 @@
+use io;
+use net::ip;
+use net;
+use os;
+use rt;
+
+// Opens a TCP connection to the given host and port. Blocks until the
+// connection is established.
+export fn connect(
+ addr: ip::addr,
+ port: u16,
+ options: net::connect_option...
+) (*io::stream | io::error) = {
+ const sockaddr = ip::to_native(addr, port);
+ const sockfd = net::connect_fd(sockaddr, options...)?;
+ return os::fdopen(sockfd, ip::string(addr),
+ io::mode::READ | io::mode::WRITE);
+};
+
+// Binds a TCP listener to the given address.
+export fn listen(
+ addr: ip::addr,
+ port: u16,
+ options: net::listen_option...
+) (*net::listener | io::error) = {
+ let sockaddr = ip::to_native(addr, port);
+ let sockfd = net::listen_fd(sockaddr, options...)?;
+ return alloc(net::stream_listener {
+ l = net::listener {
+ accept = &net::stream_accept,
+ shutdown = &net::stream_shutdown,
+ },
+ fd = sockfd,
+ }): *net::listener;
+};
+
+// 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,
+ };
+ let sn = rt::sockaddr {...};
+ let sz = size(rt::sockaddr): u32;
+ if (rt::getpeername(fd, &sn, &sz) is rt::errno) {
+ return;
+ };
+ return ip::from_native(sn);
+};
diff --git a/net/unix/+linux.ha b/net/unix/+linux.ha
@@ -1,5 +1,11 @@
+use errors;
+use fmt;
+use io;
+use net;
+use os;
use rt;
use strings;
+use types;
// Converts a UNIX socket address to a native sockaddr.
export fn to_native(addr: addr) (rt::sockaddr | invalid) = {
@@ -29,3 +35,39 @@ export fn from_native(a: rt::sockaddr) addr = {
* => abort("Wrong address family!"),
};
};
+
+// 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) = {
+ let sockaddr = match (to_native(addr)) {
+ a: rt::sockaddr => a,
+ invalid => return errors::unsupported, // path too long
+ };
+ const sockfd = net::connect_fd(sockaddr, options...)?;
+ 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.
+export fn listen(
+ addr: addr,
+ options: net::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...)?;
+ return alloc(net::stream_listener {
+ l = net::listener {
+ accept = &net::stream_accept,
+ shutdown = &net::stream_shutdown,
+ },
+ fd = sockfd,
+ }): *net::listener;
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -544,10 +544,10 @@ linux_vdso() {
net() {
printf '# net\n'
gen_srcs net \
- '$(PLATFORM)/socket.ha' \
- '$(PLATFORM)/util.ha' \
- socket.ha
- gen_ssa net io os strings net::ip net::unix errors
+ '$(PLATFORM).ha' \
+ options.ha \
+ listener.ha
+ gen_ssa net io os strings net::ip errors rt fmt
}
gensrcs_net_ip() {
@@ -568,12 +568,19 @@ net_ip() {
gen_ssa net::ip bytes io strconv strings strio fmt
}
+net_tcp() {
+ printf '# net::tcp\n'
+ gen_srcs net::tcp \
+ '$(PLATFORM).ha'
+ gen_ssa net::tcp io net net::ip os rt
+}
+
net_unix() {
printf '# net::unix\n'
gen_srcs net::unix \
addr.ha \
'$(PLATFORM).ha'
- gen_ssa net::unix strings
+ gen_ssa net::unix net errors os io strings types fmt
}
math_random() {
@@ -793,6 +800,7 @@ linux::io_uring
linux::vdso
net
net::ip
+net::tcp
net::unix
math::random
os
diff --git a/stdlib.mk b/stdlib.mk
@@ -249,6 +249,10 @@ hare_stdlib_deps+=$(stdlib_net)
stdlib_net_ip=$(HARECACHE)/net/ip/net_ip.o
hare_stdlib_deps+=$(stdlib_net_ip)
+# gen_lib net::tcp
+stdlib_net_tcp=$(HARECACHE)/net/tcp/net_tcp.o
+hare_stdlib_deps+=$(stdlib_net_tcp)
+
# gen_lib net::unix
stdlib_net_unix=$(HARECACHE)/net/unix/net_unix.o
hare_stdlib_deps+=$(stdlib_net_unix)
@@ -798,11 +802,11 @@ $(HARECACHE)/linux/vdso/linux_vdso.ssa: $(stdlib_linux_vdso_srcs) $(stdlib_rt) $
# net
# net
stdlib_net_srcs= \
- $(STDLIB)/net/$(PLATFORM)/socket.ha \
- $(STDLIB)/net/$(PLATFORM)/util.ha \
- $(STDLIB)/net/socket.ha
+ $(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_net_unix) $(stdlib_errors)
+$(HARECACHE)/net/net.ssa: $(stdlib_net_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_os) $(stdlib_strings) $(stdlib_net_ip) $(stdlib_errors) $(stdlib_rt) $(stdlib_fmt)
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet \
@@ -819,13 +823,24 @@ $(HARECACHE)/net/ip/net_ip.ssa: $(stdlib_net_ip_srcs) $(stdlib_rt) $(stdlib_byte
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::ip \
-t$(HARECACHE)/net/ip/net_ip.td $(stdlib_net_ip_srcs)
+# net::tcp
+# net::tcp
+stdlib_net_tcp_srcs= \
+ $(STDLIB)/net/tcp/$(PLATFORM).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'
+ @mkdir -p $(HARECACHE)/net/tcp
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::tcp \
+ -t$(HARECACHE)/net/tcp/net_tcp.td $(stdlib_net_tcp_srcs)
+
# net::unix
# net::unix
stdlib_net_unix_srcs= \
$(STDLIB)/net/unix/addr.ha \
$(STDLIB)/net/unix/$(PLATFORM).ha
-$(HARECACHE)/net/unix/net_unix.ssa: $(stdlib_net_unix_srcs) $(stdlib_rt) $(stdlib_strings)
+$(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'
@mkdir -p $(HARECACHE)/net/unix
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::unix \
@@ -1299,6 +1314,10 @@ hare_testlib_deps+=$(testlib_net)
testlib_net_ip=$(TESTCACHE)/net/ip/net_ip.o
hare_testlib_deps+=$(testlib_net_ip)
+# gen_lib net::tcp
+testlib_net_tcp=$(TESTCACHE)/net/tcp/net_tcp.o
+hare_testlib_deps+=$(testlib_net_tcp)
+
# gen_lib net::unix
testlib_net_unix=$(TESTCACHE)/net/unix/net_unix.o
hare_testlib_deps+=$(testlib_net_unix)
@@ -1868,11 +1887,11 @@ $(TESTCACHE)/linux/vdso/linux_vdso.ssa: $(testlib_linux_vdso_srcs) $(testlib_rt)
# net
# net
testlib_net_srcs= \
- $(STDLIB)/net/$(PLATFORM)/socket.ha \
- $(STDLIB)/net/$(PLATFORM)/util.ha \
- $(STDLIB)/net/socket.ha
+ $(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_net_unix) $(testlib_errors)
+$(TESTCACHE)/net/net.ssa: $(testlib_net_srcs) $(testlib_rt) $(testlib_io) $(testlib_os) $(testlib_strings) $(testlib_net_ip) $(testlib_errors) $(testlib_rt) $(testlib_fmt)
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet \
@@ -1890,13 +1909,24 @@ $(TESTCACHE)/net/ip/net_ip.ssa: $(testlib_net_ip_srcs) $(testlib_rt) $(testlib_b
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::ip \
-t$(TESTCACHE)/net/ip/net_ip.td $(testlib_net_ip_srcs)
+# net::tcp
+# net::tcp
+testlib_net_tcp_srcs= \
+ $(STDLIB)/net/tcp/$(PLATFORM).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'
+ @mkdir -p $(TESTCACHE)/net/tcp
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::tcp \
+ -t$(TESTCACHE)/net/tcp/net_tcp.td $(testlib_net_tcp_srcs)
+
# net::unix
# net::unix
testlib_net_unix_srcs= \
$(STDLIB)/net/unix/addr.ha \
$(STDLIB)/net/unix/$(PLATFORM).ha
-$(TESTCACHE)/net/unix/net_unix.ssa: $(testlib_net_unix_srcs) $(testlib_rt) $(testlib_strings)
+$(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'
@mkdir -p $(TESTCACHE)/net/unix
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::unix \