ref: efb728382350bd8ee067cc1135b7e9f98581ca65
dir: /lib/std/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"
;;
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")
if port.len == 0
-> `Fail "missing port"
;;
socktype = sys.Sockstream
elif sleq(proto, "udp")
if port.len == 0
-> `Fail "missing port"
;;
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, "")
;;
}