ref: 3699a6c3daf7648653b3e4936f39bc6061331446
dir: /libstd/dial+posixy.myr/
use sys use "alloc.use" use "chartype.use" use "die.use" use "endian.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 "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 sa4 : sys.sockaddr_in var sa6 : sys.sockaddr_in6 var sa : sys.sockaddr# var sock match parsedial(str) | `Ok val: (proto, host, port) = val | `Fail m: -> `Fail m ;; match getaddr(host) | `Ipv4 bits: sa4.fam = sys.Afinet sa4.addr = bits sa4.port = hosttonet(port) sa = &sa4 castto(sys.sockaddr#) | `Ipv6 bits: sa6.fam = sys.Afinet6 sa6.addr = bits sa6.port = hosttonet(port) sa = &sa6 castto(sys.sockaddr#) ;; sock = sys.socket(sa.fam, proto, 0) if sock < 0 -> `Fail "failed to connect to socket" ;; var err err = sys.connect(sock, sa, sizeof(sys.sockaddr_in)) if err < 0 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, "") ;; }