ref: a832e3d49570feddfe89fc31f3c08f73126fa04e
parent: 8303e07068b39bb6de362eafff89c7a3a53206cc
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Apr 25 18:51:55 EDT 2016
Add listen/accept impl. Works on FreeBSD, at least.
--- a/lib/std/bld.sub
+++ b/lib/std/bld.sub
@@ -77,19 +77,21 @@
memops-impl+plan9-x64.s
# platform specific files
- env+plan9.myr
- env+posixy.myr
- errno+plan9.myr
+ dial+plan9.myr
+ dial+posixy.myr
+ dialparse+posixy.myr
dir+freebsd.myr
dir+linux.myr
dir+osx.myr
dir+plan9.myr
- wait+posixy.myr
- wait+plan9.myr
- dial+posixy.myr
- dial+plan9.myr
- resolve+posixy.myr
+ env+plan9.myr
+ env+posixy.myr
+ errno+plan9.myr
+ listen+posixy.myr
resolve+plan9.myr
+ resolve+posixy.myr
+ wait+plan9.myr
+ wait+posixy.myr
# relatively generic syscall wrappers
syswrap+plan9.myr
--- a/lib/std/dial+posixy.myr
+++ b/lib/std/dial+posixy.myr
@@ -2,13 +2,10 @@
use "alloc"
use "chartype"
+use "dialparse"
use "die"
use "endian"
-use "hasprefix"
-use "intparse"
-use "ipparse"
use "option"
-use "resolve"
use "result"
use "slcp"
use "sleq"
@@ -18,7 +15,7 @@
use "utf"
pkg std =
- const dial : (dialstr : byte[:] -> result(fd, byte[:]))
+ const dial : (ds : byte[:] -> result(fd, byte[:]))
;;
/*
@@ -33,9 +30,6 @@
/* 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)
@@ -48,14 +42,15 @@
var sa4 : sys.sockaddr_in
var sa6 : sys.sockaddr_in6
var sa : sys.sockaddr#
- var host, portstr, port
+ var hoststr, portstr, port
var sock, sz
+ var err
match nameseg(str)
| `None: -> `Fail "required host!port for ip dial"
| `Some ("", _): -> `Fail "empty host"
- | `Some (_, ""): -> `Fail "empty host"
- | `Some segs: (host, portstr) = segs
+ | `Some (_, ""): -> `Fail "empty port"
+ | `Some segs: (hoststr, portstr) = segs
;;
match parseport(portstr)
@@ -63,7 +58,7 @@
| `None: -> `Fail("invalid port")
;;
- match getaddr(host)
+ match getaddr(hoststr)
| `Ok `Ipv4 bits:
sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)]
sa = &sa4 castto(sys.sockaddr#)
@@ -76,11 +71,10 @@
-> `Fail m
;;
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)
@@ -104,59 +98,8 @@
-> `Fail "failed to create socket"
;;
slcp(sa.path[:path.len], path)
- if sys.bind(sock, &sa castto(sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
+ if sys.connect(sock, &sa castto(sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
-> `Fail "failed to bind address"
;;
-> `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:
- if hi.len > 0
- ip = hi[0].addr
- slfree(hi)
- else
- slfree(hi)
- -> `Fail "no hosts resolved for addr"
- ;;
- | `Fail m:
- -> `Fail "could not get host info"
- ;;
- ;;
- -> `Ok ip
-}
-
-const nameseg = {str
- match strfind(str, "!")
- | `Some idx:
- -> `Some (str[:idx], str[idx+1:])
- | `None:
- -> `None
- ;;
-}
-
--- /dev/null
+++ b/lib/std/dialparse+posixy.myr
@@ -1,0 +1,69 @@
+use "alloc"
+use "chartype"
+use "hasprefix"
+use "intparse"
+use "slcp"
+use "sleq"
+use "strfind"
+use "striter"
+use "option"
+use "result"
+use "ipparse"
+use "resolve"
+
+pkg std =
+ pkglocal const parseport : (port : byte[:] -> option(uint16))
+ pkglocal const getaddr : (addr : byte[:] -> result(netaddr, byte[:]))
+ pkglocal const nameseg : (str : byte[:] -> option((byte[:], byte[:])))
+;;
+
+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:
+ if hi.len > 0
+ ip = hi[0].addr
+ slfree(hi)
+ else
+ slfree(hi)
+ -> `Fail "no hosts resolved for addr"
+ ;;
+ | `Fail m:
+ -> `Fail "could not get host info"
+ ;;
+ ;;
+ -> `Ok ip
+}
+
+const nameseg = {str
+ match strfind(str, "!")
+ | `Some idx:
+ -> `Some (str[:idx], str[idx+1:])
+ | `None:
+ -> `None
+ ;;
+}
+
--- /dev/null
+++ b/lib/std/listen+posixy.myr
@@ -1,0 +1,125 @@
+use sys
+
+use "alloc"
+use "chartype"
+use "dialparse"
+use "die"
+use "endian"
+use "option"
+use "resolve"
+use "result"
+use "slcp"
+use "sleq"
+use "strfind"
+use "striter"
+use "syswrap"
+use "utf"
+
+pkg std =
+ const announce : (ds : byte[:] -> result(fd, byte[:]))
+ const listen : (sock : fd -> result(fd, byte[:]))
+ const accept : (lfd : fd -> result(fd, byte[:]))
+;;
+
+const announce = {ds
+ match nameseg(ds)
+ | `Some ("tcp", str): -> announcesock(sys.Sockstream, str)
+ | `Some ("udp", str): -> announcesock(sys.Sockdgram, str)
+ | `Some ("unix", str): -> announceunix(str)
+ | `Some (proto, str): -> `Fail "unknown protocol"
+ | `None: -> `Fail "missing protocol"
+ ;;
+}
+
+const announcesock = {proto, str
+ var sa4 : sys.sockaddr_in
+ var sa6 : sys.sockaddr_in6
+ var sa : sys.sockaddr#
+ var hoststr, portstr, port
+ var sock, sz
+ var yes
+
+ match nameseg(str)
+ | `None: -> `Fail "required addr!port for ip listen"
+ | `Some ("", _): -> `Fail "empty host"
+ | `Some (_, ""): -> `Fail "empty port"
+ | `Some segs: (hoststr, portstr) = segs
+ ;;
+
+ match parseport(portstr)
+ | `Some p: port = p
+ | `None: -> `Fail("invalid port")
+ ;;
+
+ if std.sleq(hoststr, "*")
+ sa6=[.fam=sys.Afinet6, .port=hosttonet(port)]
+ sa = &sa6 castto(sys.sockaddr#)
+ sz = sizeof(sys.sockaddr_in6)
+ else
+ match getaddr(hoststr)
+ | `Ok `Ipv4 bits:
+ sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)]
+ sa = &sa4 castto(sys.sockaddr#)
+ sz = sizeof(sys.sockaddr_in)
+ | `Ok `Ipv6 bits:
+ sa6=[.fam=sys.Afinet6, .addr=bits, .port=hosttonet(port)]
+ sa = &sa6 castto(sys.sockaddr#)
+ sz = sizeof(sys.sockaddr_in6)
+ | `Fail m:
+ -> `Fail m
+ ;;
+ ;;
+ sock = sys.socket(sa.fam, proto, 0)
+ if sock < 0
+ -> `Fail "failed to create socket"
+ ;;
+ yes = 1
+ if sys.setsockopt(sock, sys.Solsock, sys.Soreuseaddr, &yes castto(void#), sizeof(int)) < 0
+ -> `Fail "failed to set sock opts"
+ ;;
+ if sys.bind(sock, sa, sz) < 0
+ -> `Fail "failed to bind socket"
+ ;;
+ -> `Ok sock castto(fd)
+}
+
+const announceunix = {path
+ var sa : sys.sockaddr_un
+ var sock
+
+ sa = [.fam = sys.Afunix]
+ if path.len >= sa.path.len
+ -> `Fail "path too long"
+ ;;
+
+ slcp(sa.path[:path.len], path)
+ sock = sys.socket(sys.Afunix, sys.Sockstream, 0)
+ if sock < 0
+ -> `Fail "failed to create socket"
+ ;;
+ if sys.bind(sock, &sa castto(sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
+ -> `Fail "failed to bind address"
+ ;;
+ -> `Ok (sock castto(fd))
+
+}
+
+const listen = {sock : std.fd -> result(fd, byte[:])
+ if sys.listen(sock castto(sys.fd), 10) < 0
+ -> `Fail "unable to listen on socket"
+ ;;
+ -> `Ok (sys.dup(sock castto(sys.fd)) castto(fd))
+}
+
+const accept = {lfd
+ var sa : sys.sockaddr_storage
+ var len : sys.size
+ var fd
+
+ fd = sys.accept(lfd castto(sys.fd), 0 castto(sys.sockaddr#), 0 castto(sys.size#))
+ if fd < 0
+ -> `Fail "unable to accept socket"
+ ;;
+ -> `Ok (fd castto(fd))
+}
+
--- a/lib/sys/sys+freebsd-x64.myr
+++ b/lib/sys/sys+freebsd-x64.myr
@@ -9,6 +9,7 @@
type mprot = int64 /* memory protection */
type mopt = int64 /* memory mapping options */
type socktype = int64 /* socket type */
+ type sockopt = int64 /* socket option */
type sockproto = int64 /* socket protocol */
type sockfam = uint8 /* socket family */
type filemode = uint16
@@ -218,7 +219,26 @@
const Sockraw : socktype = 3
const Sockrdm : socktype = 4
const Sockseqpacket : socktype = 5
+ const Solsock : socktype = 0xffff
+ /* socket options */
+ const Sodebug : sockopt = 0x0001 /* turn on debugging info recording */
+ const Soacceptconn : sockopt = 0x0002 /* socket has had listen() */
+ const Soreuseaddr : sockopt = 0x0004 /* allow local address reuse */
+ const Sokeepalive : sockopt = 0x0008 /* keep connections alive */
+ const Sodontroute : sockopt = 0x0010 /* just use interface addresses */
+ const Sobroadcast : sockopt = 0x0020 /* permit sending of broadcast msgs */
+ const Souseloopback : sockopt = 0x0040 /* bypass hardware when possible */
+ const Solinger : sockopt = 0x0080 /* linger on close if data present */
+ const Sooobinline : sockopt = 0x0100 /* leave received OOB data in line */
+ const Soreuseport : sockopt = 0x0200 /* allow local address & port reuse */
+ const Sotimestamp : sockopt = 0x0400 /* timestamp received dgram traffic */
+ const Sonosigpipe : sockopt = 0x0800 /* no SIGPIPE from EPIPE */
+ const Soacceptfilter : sockopt = 0x1000 /* there is an accept filter */
+ const Sobintime : sockopt = 0x2000 /* timestamp received dgram traffic */
+ const Sonooffload : sockopt = 0x4000 /* socket cannot be offloaded */
+ const Sonoddp : sockopt = 0x8000 /* disable direct data placement */
+
/* network protocols */
const Ipproto_ip : sockproto = 0
const Ipproto_icmp : sockproto = 1
@@ -744,6 +764,8 @@
const accept : (sock : fd, addr : sockaddr#, len : size# -> fd)
const listen : (sock : fd, backlog : int -> int)
const bind : (sock : fd, addr : sockaddr#, len : size -> int)
+ const setsockopt : (sock : fd, lev : socktype, opt : sockopt, val : void#, len : size -> int)
+ const getsockopt : (sock : fd, lev : socktype, opt : sockopt, val : void#, len : size# -> int)
/* memory mapping */
const munmap : (addr:byte#, len:size -> int64)
@@ -866,6 +888,8 @@
const accept = {sock, addr, len; -> syscall(Sysaccept, a(sock), a(addr), a(len)) castto(fd)}
const listen = {sock, backlog; -> syscall(Syslisten, a(sock), a(backlog)) castto(int)}
const bind = {sock, addr, len; -> syscall(Sysbind, a(sock), a(addr), a(len)) castto(int)}
+const setsockopt = {sock, lev, opt, val, len; -> syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) castto(int)}
+const getsockopt = {sock, lev, opt, val, len; -> syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) castto(int)}
/* memory management */
const munmap = {addr, len; -> syscall(Sysmunmap, a(addr), a(len))}
--- a/lib/sys/sys+linux-x64.myr
+++ b/lib/sys/sys+linux-x64.myr
@@ -220,7 +220,33 @@
const Sockseqpacket : socktype = 5 /* sequenced, reliable packets */
const Sockdccp : socktype = 6 /* data congestion control protocol */
const Sockpack : socktype = 10 /* linux specific packet */
+ const Solsock : socktype = 1
+ /* socket options */
+ const Sodebug : sockopt = 1
+ const Soreuseaddr : sockopt = 2
+ const Sotype : sockopt = 3
+ const Soerror : sockopt = 4
+ const Sodontroute : sockopt = 5
+ const Sobroadcast : sockopt = 6
+ const Sosndbuf : sockopt = 7
+ const Sorcvbuf : sockopt = 8
+ const Sosndbufforce : sockopt = 32
+ const Sorcvbufforce : sockopt = 33
+ const Sokeepalive : sockopt = 9
+ const Sooobinline : sockopt = 10
+ const Sono_check : sockopt = 11
+ const Sopriority : sockopt = 12
+ const Solinger : sockopt = 13
+ const Sobsdcompat : sockopt = 14
+ const Soreuseport : sockopt = 15
+ const Sopasscred : sockopt = 16
+ const Sopeercred : sockopt = 17
+ const Sorcvlowat : sockopt = 18
+ const Sosndlowat : sockopt = 19
+ const Sorcvtimeo : sockopt = 20
+ const Sosndtimeo : sockopt = 21
+
/* network protocols */
const Ipproto_ip : sockproto = 0
const Ipproto_icmp : sockproto = 1
@@ -673,6 +699,8 @@
const accept : (sock : fd, addr : sockaddr#, len : size# -> fd)
const listen : (sock : fd, backlog : int -> int)
const bind : (sock : fd, addr : sockaddr#, len : size -> int)
+ const setsockopt : (sock : fd, lev : socktype, opt : sockopt, val : void#, len : size -> int)
+ const getsockopt : (sock : fd, lev : socktype, opt : sockopt, val : void#, len : size# -> int)
/* memory mapping */
const munmap : (addr:byte#, len:size -> int64)