summaryrefslogtreecommitdiff
path: root/lib/std/dial+plan9.myr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/dial+plan9.myr')
-rw-r--r--lib/std/dial+plan9.myr165
1 files changed, 165 insertions, 0 deletions
diff --git a/lib/std/dial+plan9.myr b/lib/std/dial+plan9.myr
new file mode 100644
index 0000000..35d97e9
--- /dev/null
+++ b/lib/std/dial+plan9.myr
@@ -0,0 +1,165 @@
+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)
+}
+