ref: a72122d49d80fae5d7ffce3a7eeb47b320b9f2c6
dir: /lib/std/dial+posixy.myr/
use sys use "alloc" use "chartype" use "die" use "endian" use "hasprefix" use "intparse" use "ipparse" use "option" use "resolve" use "result" use "sleq" use "slcp" use "strfind" use "syswrap" use "utf" pkg std = const dial : (dialstr : byte[:] -> result(fd, byte[:])) ;; /* a map from service name to a list of (port,proto) pairs in order of preference */ /* FIXME: implement var services : htab(byte[:], [int, byte[:]][:])# var inited = false */ /* takes a plan 9 style dial string */ const dial = {ds match nameseg(ds) /* | `Some ("net", str): -> guessdial(str) */ | `Some ("tcp", str): -> dialsock(sys.Sockstream, str) | `Some ("udp", str): -> dialsock(sys.Sockdgram, str) | `Some ("unix", u): -> dialunix(u) | `Some (proto, str): -> `Fail "unknown protocol" | `None: -> `Fail "missing protocol" ;; } const dialsock = {proto, str var sa4 : sys.sockaddr_in var sa6 : sys.sockaddr_in6 var sa : sys.sockaddr# var host, portstr, port var sock, sz match nameseg(str) | `std.None: -> `Fail "required host!port for ip dial" | `std.Some ("", _): -> `Fail "empty host" | `std.Some (_, ""): -> `Fail "empty host" | `std.Some segs: (host, portstr) = segs ;; match parseport(portstr) | `std.Some p: port = p | `std.None: -> `Fail("invalid port") ;; match getaddr(host) | `Ipv4 bits: sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)] sa = &sa4 castto(sys.sockaddr#) sz = sizeof(sys.sockaddr_in) | `Ipv6 bits: sa6=[.fam=sys.Afinet6, .addr=bits, .port=hosttonet(port)] sa = &sa6 castto(sys.sockaddr#) sz = sizeof(sys.sockaddr_in6) ;; sock = sys.socket(sa.fam, proto, 0) if sock < 0 -> `Fail "failed to create socket" ;; var err err = sys.connect(sock, sa, sz) if err < 0 sys.close(sock) -> `Fail "Failed to bind socket" ;; -> `Ok (sock castto(fd)) } const dialunix = {path var sa : sys.sockaddr_un var sock sa = [.fam = sys.Afunix] if path.len >= sa.path.len -> `Fail "path too long" ;; sock = sys.socket(sys.Afunix, sys.Sockstream, 0) if sock < 0 -> `Fail "failed to create socket" ;; std.slcp(sa.path[:path.len], path) if sys.bind(sock, &sa castto(sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0 -> `Fail "failed to bind address" ;; -> `std.Ok (sock castto(fd)) } const parseport = {port match intparse(port) | `Some n: -> `Some n | `None: /* a small number of hardcoded ports */ if sleq(port, "http") -> `Some 80 elif sleq(port, "https") -> `Some 443 elif sleq(port, "ircd") -> `Some 6667 elif sleq(port, "dns") -> `Some 53 ;; ;; -> `None } const getaddr = {addr var ip match ipparse(addr) | `Some a: ip = a | `None: match resolve(addr) | `Ok hi: ip = hi[0].addr slfree(hi) | `Fail m: ;; ;; -> ip } const nameseg = {str match strfind(str, "!") | `Some idx: -> `Some (str[:idx], str[idx+1:]) | `None: -> `None ;; }