ref: d60e706a5f499863320b9359519438c62a4df303
dir: /lib/std/dial+plan9.myr/
use sys use "alloc.use" use "die.use" use "fmt.use" use "option.use" use "pathjoin.use" use "result.use" use "sleq.use" use "strfind.use" use "strstrip.use" use "syswrap.use" use "utf.use" pkg std = const dial : (dialstr : byte[:] -> result(fd, byte[:])) ;; const Maxpath = 512 const dial = {str var netdir, proto, rem (netdir, proto, rem) = parsedial(str) if netdir.len != 0 -> csdial(netdir, proto, rem) ;; match csdial("/net", proto, rem) | `Ok fd: -> `Ok fd | `Fail m: -> csdial("/net.alt", proto, rem) ;; } const csdial = {netdir, proto, rem var dir, clone, addr, csaddr var ret, csfd, n var buf : byte[Maxpath] /* Try using the connection server */ dir = fmt("{}/cs", netdir) csfd = open(dir, Ordwr) if csfd < 0 clone = fmt("{}/{}/clone", netdir, proto) ret = call(clone, rem, netdir) slfree(clone) if ret == -1 -> `Fail "unable to dial without cs" else -> `Ok ret ;; ;; slfree(dir) csaddr = fmt("{}!{}", proto, rem) if write(csfd, csaddr) < 0 close(csfd) -> `Fail "couldn't blah cs" ;; slfree(csaddr) seek(csfd, 0, 0) while true n = read(csfd, buf[:]) if n <= 0 break ;; match strfind(buf[:n], " ") | `None: continue | `Some i: clone = buf[:i] addr = buf[i+1:n] ;; ret = call(clone, addr, netdir) if ret >= 0 break ;; ;; close(csfd) if ret < 0 -> `Fail "unable to dial" ;; -> `Ok ret } const call = {clone, addr, netdir var namebuf : byte[Maxpath] var databuf : byte[Maxpath] var name, base, dpath var cfd, datafd var c, n datafd = -1 c = nsclonestr(clone, netdir) cfd = open(c, Ordwr) if cfd < 0 goto cleanup ;; n = read(cfd, namebuf[:]) if n < 0 goto cleanup ;; fput(cfd, "connect {}", addr) name = strstrip(namebuf[:n]) match strrfind(c, "/") | `None: die("there should be a '/' here\n") | `Some i: base = c[:i] ;; dpath = bfmt(databuf[:], "{}/{}/data", base, name) datafd = open(dpath, Ordwr) :cleanup close(cfd) slfree(c) -> datafd } const nsclonestr = {clone, netdir if decode(clone) == '#' || decode(clone) == '/' match std.strfind(clone[1:], "/") | `Some i: clone = clone[i+1:] | `None: /* nothing */ ;; ;; -> pathcat(netdir, clone) } const parsedial = {str var netdir, proto, rem, hd, tl netdir="" proto = "" rem = "" match strfind(str, "!") | `None: proto = "net" rem = str | `Some sep: hd = str[:sep] tl = str[sep+1:] if decode(hd) == '#' || decode(hd) == '/' match strrfind(hd, "/") | `Some idx: netdir = hd[:idx] proto = hd[idx+1:] | `None: netdir = "" proto = hd ;; else netdir = "" proto = hd ;; rem = tl ;; -> (netdir, proto, rem) }