summaryrefslogtreecommitdiff
path: root/lib/std/dial+posixy.myr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/dial+posixy.myr')
-rw-r--r--lib/std/dial+posixy.myr147
1 files changed, 147 insertions, 0 deletions
diff --git a/lib/std/dial+posixy.myr b/lib/std/dial+posixy.myr
new file mode 100644
index 0000000..13f0257
--- /dev/null
+++ b/lib/std/dial+posixy.myr
@@ -0,0 +1,147 @@
+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"
+ 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"
+ ;;
+
+ -> `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, "")
+ ;;
+}
+