ref: 14c0d8b03e8390c4f06bde071294a0c2325e8c7f
dir: /libstd/dial.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 "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 socktype, portnum var sa : sys.sockaddr_in /* we only support inet sockets right now.. ugh. */ var sock (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" ;; match getaddr(host) | `Ipv4 bits: sa.fam = sys.Afinet sa.addr = bits sa.port = hosttonet(portnum) | `Ipv6 bits: -> `Fail "ipv6 not yet supported" ;; sock = sys.socket(sa.fam, socktype, 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 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 var len for len = 0; len < str.len; len++ if str[len] == '!' castto(byte) -> (str[:len], str[len+1:]) ;; ;; -> (str[:], str[len:]) }