ref: 8e1b57e6cb50118d28a86115520b7331cc0fdf23
dir: /lib/std/dial+posixy.myr/
use sys
use "alloc"
use "chartype"
use "die"
use "endian"
use "hasprefix"
use "intparse"
use "ipparse"
use "option"
use "resolve"
use "result"
use "slcp"
use "sleq"
use "strfind"
use "striter"
use "syswrap"
use "utf"
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 = {ds
match nameseg(ds)
/*
| `Some ("net", str): -> guessdial(str)
*/
| `Some ("tcp", str): -> dialsock(sys.Sockstream, str)
| `Some ("udp", str): -> dialsock(sys.Sockdgram, str)
| `Some ("unix", u): -> dialunix(u)
| `Some (proto, str): -> `Fail "unknown protocol"
| `None: -> `Fail "missing protocol"
;;
}
const dialsock = {proto, str
var sa4 : sys.sockaddr_in
var sa6 : sys.sockaddr_in6
var sa : sys.sockaddr#
var host, portstr, port
var sock, sz
match nameseg(str)
| `std.None: -> `Fail "required host!port for ip dial"
| `std.Some ("", _): -> `Fail "empty host"
| `std.Some (_, ""): -> `Fail "empty host"
| `std.Some segs: (host, portstr) = segs
;;
match parseport(portstr)
| `std.Some p: port = p
| `std.None: -> `Fail("invalid port")
;;
match getaddr(host)
| `Ipv4 bits:
sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)]
sa = &sa4 castto(sys.sockaddr#)
sz = sizeof(sys.sockaddr_in)
| `Ipv6 bits:
sa6=[.fam=sys.Afinet6, .addr=bits, .port=hosttonet(port)]
sa = &sa6 castto(sys.sockaddr#)
sz = sizeof(sys.sockaddr_in6)
;;
sock = sys.socket(sa.fam, proto, 0)
if sock < 0
-> `Fail "failed to create socket"
;;
var err
err = sys.connect(sock, sa, sz)
if err < 0
sys.close(sock)
-> `Fail "Failed to bind socket"
;;
-> `Ok (sock castto(fd))
}
const dialunix = {path
var sa : sys.sockaddr_un
var sock
sa = [.fam = sys.Afunix]
if path.len >= sa.path.len
-> `Fail "path too long"
;;
sock = sys.socket(sys.Afunix, sys.Sockstream, 0)
if sock < 0
-> `Fail "failed to create socket"
;;
std.slcp(sa.path[:path.len], path)
if sys.bind(sock, &sa castto(sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
-> `Fail "failed to bind address"
;;
-> `std.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
match strfind(str, "!")
| `Some idx:
-> `Some (str[:idx], str[idx+1:])
| `None:
-> `None
;;
}