shithub: mc

ref: 1c61d05cba15d7e93d3207d4f3ab3c6043d63b77
dir: /lib/std/dial+posixy.myr/

View raw version
use sys

use "alloc"
use "chartype"
use "dialparse"
use "die"
use "endian"
use "option"
use "result"
use "slcp"
use "sleq"
use "strfind"
use "striter"
use "syswrap"
use "utf"

pkg std =
	const dial	: (ds : 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):	-> dialsock(sys.Sockstream, str)
	| `Some ("tcp", str):	-> dialsock(sys.Sockstream, str)
	| `Some ("udp", str):	-> dialsock(sys.Sockdgram, str)
	| `Some ("unix", u):	-> dialunix(u)
	| `Some (proto, str):	-> `Err "unknown protocol"
	| `None:	-> `Err "missing protocol"
	;;
}

const dialsock = {proto, str
	var sa4 : sys.sockaddr_in
	var sa6 : sys.sockaddr_in6
	var sa	: sys.sockaddr#
	var hoststr, portstr, port
	var sock, sz
	var err

	match nameseg(str)
	| `None:	-> `Err "required host!port for ip dial"
	| `Some ("", _):	-> `Err "empty host"
	| `Some (_, ""):	-> `Err "empty port"
	| `Some segs:	(hoststr, portstr) = segs
	;;

	match parseport(portstr)
	| `Some p:	port = p
	| `None:	-> `Err("invalid port")
	;;

	match getaddr(hoststr)
	| `Ok `Ipv4 bits:
		sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)]
		sa = (&sa4 : sys.sockaddr#)
		sz = sizeof(sys.sockaddr_in)
	| `Ok `Ipv6 bits:
		sa6=[.fam=sys.Afinet6, .addr=bits, .port=hosttonet(port)]
		sa = (&sa6 : sys.sockaddr#)
		sz = sizeof(sys.sockaddr_in6)
	| `Err m:
		-> `Err m
	;;
	sock = sys.socket(sa.fam, proto, 0)
	if sock < 0
		-> `Err "failed to create socket"
	;;

	err = sys.connect(sock, sa, sz)
	if err < 0
		sys.close(sock)
		-> `Err "Failed to bind socket"
	;;

	-> `Ok (sock : fd)
}

const dialunix = {path
	var sa : sys.sockaddr_un
	var sock
	
	sa = [.fam = sys.Afunix]
	if path.len >= sa.path.len
		-> `Err "path too long"
	;;

	sock = sys.socket(sys.Afunix, sys.Sockstream, 0)
	if sock < 0
		-> `Err "failed to create socket"
	;;
	slcp(sa.path[:path.len], path)
	if sys.connect(sock, (&sa : sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
		-> `Err "failed to bind address"
	;;
	-> `Ok (sock : fd)
}