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:
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)