ref: 526479d1064ab5daadf7b2a1aad5a00153a5d455
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 /* we only support inet sockets right now.. ugh. */ var sa6 : sys.sockaddr_in6 /* we only support inet sockets right now.. ugh. */ 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, "") ;; }