ref: e1a091f7f770a783d3847bff4fd1bb402fd8f22b
dir: /libstd/dial+posixy.myr/
use "alloc.use" use "chartype.use" use "die.use" use "endian.use" use "fmt.use" use "hasprefix.use" use "intparse.use" use "ipparse.use" use "option.use" use "resolve.use" use "result.use" use "sleq.use" use "strfind.use" use "sys.use" use "syswrap.use" use "utf.use" 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 = {str var proto, host, port var sa : sys.sockaddr_in /* we only support inet sockets right now.. ugh. */ var sock match parsedial(str) | `Ok val: (proto, host, port) = val | `Fail m: -> `Fail m ;; match getaddr(host) | `Ipv4 bits: sa.fam = sys.Afinet sa.addr = bits sa.port = hosttonet(port) | `Ipv6 bits: -> `Fail "ipv6 not yet supported" ;; sock = sys.socket(sa.fam, proto, 0) if sock < 0 -> `Fail "failed to connect to socket" ;; var err err = sys.connect(sock, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in)) if err < 0 put("Errno %i\n", -err) sys.close(sock) -> `Fail "Failed to bind socket" ;; -> `Ok (sock castto(fd)) } const parsedial = {str var proto, host, port var socktype, portnum (proto, str) = nameseg(str) (host, str) = nameseg(str) (port, str) = nameseg(str) if proto.len == 0 -> `Fail "missing proto" elif host.len == 0 -> `Fail "missing host" elif port.len == 0 -> `Fail "missing port" ;; if sleq(proto, "net") -> `Fail "net wildcard proto not yet supported\n" elif sleq(proto, "unix") -> `Fail "net unix proto not yet supported\n" elif sleq(proto, "tcp") socktype = sys.Sockstream elif sleq(proto, "udp") socktype = sys.Sockdgram ;; match parseport(port) | `Some n: portnum = n | `None: -> `Fail "bad port" ;; -> `Ok (socktype, host, portnum) } 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: -> (str[:idx], str[idx+1:]) | `None: -> (str, "") ;; }