ref: c1ad3758cdccebead9fafd8bdecf6caa5071fe19
dir: /libstd/dial+posixy.myr/
use sys 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 "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, "") ;; }