hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 7c7264d58d3cddc4ac8268dab8ddd0aa0aaeb5ee
parent 662836c2173638c78e7593e95271250eca8fb5df
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 23 Jun 2021 18:13:22 -0400

net::dial: initial implementation for TCP

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mnet/dial/dial.ha | 4++--
Mnet/dial/ip.ha | 17++++++++++++++---
Mnet/dial/registry.ha | 26+++++++++++++++++++++++++-
Mnet/dial/resolve.ha | 15+++++++++------
Mscripts/gen-stdlib | 2+-
Mstdlib.mk | 4++--
6 files changed, 53 insertions(+), 15 deletions(-)

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 | net::error) = { +) (*io::stream | error) = { for (let i = 0z; i < len(default_protocols); i += 1) { const p = default_protocols[i]; if (p.name == proto) { @@ -46,5 +46,5 @@ export fn dial( return p.dial(address, service); }; }; - return net::unknownproto; + return net::unknownproto: net::error; }; diff --git a/net/dial/ip.ha b/net/dial/ip.ha @@ -4,10 +4,21 @@ use net::ip; use net::tcp; use net::udp; -fn dial_tcp(addr: str, service: str) (*io::stream | net::error) = { - abort(); // TODO +fn dial_tcp(addr: str, service: str) (*io::stream | 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, + err: net::error => if (i + 1 >= len(addrs)) { + return err; + }, + }; + }; + abort(); // Unreachable }; -fn dial_udp(addr: str, service: str) (*io::stream | net::error) = { +fn dial_udp(addr: str, service: str) (*io::stream | error) = { abort(); // TODO }; diff --git a/net/dial/registry.ha b/net/dial/registry.ha @@ -1,8 +1,32 @@ +use errors; use io; use net; +use net::dns; + +// Returned if the address parameter was invalid, for example if it specifies an +// invalid port number. +export type invalid_address = !void; + +// Returned if the service parameter does not name a service known to the +// system. +export type unknown_service = !void; + +// Errors which can occur from dial. +export type error = !(invalid_address | unknown_service | net::error | dns::error); + +// Converts an [[error]] to a human-readable string. +export fn strerror(err: error) const str = { + // TODO: These could be better + return match (err) { + invalid_address => "Attempted to dial an invalid address", + unknown_service => "Unknown service", + err: net::error => net::strerror(err), + err: dns::error => dns::strerror(err), + }; +}; // A dialer is a function which implements dial for a specific protocol. -export type dialer = fn(addr: str, service: str) (*io::stream | net::error); +export type dialer = fn(addr: str, service: str) (*io::stream | error); type protocol = struct { name: str, diff --git a/net/dial/resolve.ha b/net/dial/resolve.ha @@ -14,7 +14,7 @@ export fn resolve( proto: str, addr: str, service: str, -) (([]ip::addr, u16) | dns::error) = { +) (([]ip::addr, u16) | error) = { let port = match (strings::index(addr, ':')) { void => match (strconv::stou16(service)) { u: u16 => u, @@ -23,8 +23,10 @@ export fn resolve( i: size => { const sub = strings::sub(addr, i, strings::end); addr = strings::sub(addr, 0, i); - // TODO: Return error on invalid port - strconv::stou16(sub)!; + match (strconv::stou16(sub)) { + u: u16 => u, + * => return invalid_address, + }; }, }; @@ -38,8 +40,9 @@ export fn resolve( // - Consult /etc/services // - Fetch the SRV record - assert(port != 0); // TODO: Return an error - + if (port == 0) { + return unknown_service; + }; if (len(addrs) == 0) { return dns::name_error; }; @@ -47,7 +50,7 @@ export fn resolve( return (addrs, port); }; -fn resolve_addr(addr: str) ([]ip::addr | dns::error) = { +fn resolve_addr(addr: str) ([]ip::addr | error) = { match (ip::parse(addr)) { addr: ip::addr => alloc([addr]), ip::invalid => void, diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -553,9 +553,9 @@ net() { net_dial() { printf '# net::dial\n' gen_srcs net::dial \ + registry.ha \ dial.ha \ ip.ha \ - registry.ha \ resolve.ha gen_ssa net::dial io net net::ip net::tcp net::udp net::dns } diff --git a/stdlib.mk b/stdlib.mk @@ -835,9 +835,9 @@ $(HARECACHE)/net/net.ssa: $(stdlib_net_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_ # net::dial # net::dial stdlib_net_dial_srcs= \ + $(STDLIB)/net/dial/registry.ha \ $(STDLIB)/net/dial/dial.ha \ $(STDLIB)/net/dial/ip.ha \ - $(STDLIB)/net/dial/registry.ha \ $(STDLIB)/net/dial/resolve.ha $(HARECACHE)/net/dial/net_dial.ssa: $(stdlib_net_dial_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_net) $(stdlib_net_ip) $(stdlib_net_tcp) $(stdlib_net_udp) $(stdlib_net_dns) @@ -2005,9 +2005,9 @@ $(TESTCACHE)/net/net.ssa: $(testlib_net_srcs) $(testlib_rt) $(testlib_io) $(test # net::dial # net::dial testlib_net_dial_srcs= \ + $(STDLIB)/net/dial/registry.ha \ $(STDLIB)/net/dial/dial.ha \ $(STDLIB)/net/dial/ip.ha \ - $(STDLIB)/net/dial/registry.ha \ $(STDLIB)/net/dial/resolve.ha $(TESTCACHE)/net/dial/net_dial.ssa: $(testlib_net_dial_srcs) $(testlib_rt) $(testlib_io) $(testlib_net) $(testlib_net_ip) $(testlib_net_tcp) $(testlib_net_udp) $(testlib_net_dns)