hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

+freebsd.ha (3684B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use errors;
      5 use io;
      6 use net;
      7 use net::ip;
      8 use os;
      9 use rt;
     10 
     11 // Opens a TCP connection to the given host and port. Blocks until the
     12 // connection is established.
     13 export fn connect(
     14 	addr: ip::addr,
     15 	port: u16,
     16 	options: connect_option...
     17 ) (net::socket | net::error) = {
     18 	const sockaddr = ip::to_native(addr, port);
     19 	const family = match (addr) {
     20 	case ip::addr4 =>
     21 		yield rt::AF_INET: int;
     22 	case ip::addr6 =>
     23 		yield rt::AF_INET6: int;
     24 	};
     25 	let f = 0i;
     26 	for (let i = 0z; i < len(options); i += 1) {
     27 		match (options[i]) {
     28 		case let fl: net::sockflag =>
     29 			f |= fl;
     30 		case => void;
     31 		};
     32 	};
     33 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     34 	const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
     35 	case let err: rt::errno =>
     36 		return errors::errno(err);
     37 	case let fd: int =>
     38 		yield fd;
     39 	};
     40 
     41 	for (let i = 0z; i < len(options); i += 1) {
     42 		match (options[i]) {
     43 		case keepalive =>
     44 			setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
     45 		case => void;
     46 		};
     47 	};
     48 	const sz = ip::native_addrlen(addr);
     49 	match (rt::connect(sockfd, &sockaddr, sz)) {
     50 	case let err: rt::errno =>
     51 		if (err != rt::EINPROGRESS) {
     52 			return errors::errno(err);
     53 		};
     54 		assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK);
     55 	case int => void;
     56 	};
     57 	return io::fdopen(sockfd);
     58 };
     59 
     60 // Binds a TCP socket to the given address.
     61 export fn listen(
     62 	addr: ip::addr,
     63 	port: u16,
     64 	options: listen_option...
     65 ) (net::socket | net::error) = {
     66 	const sockaddr = ip::to_native(addr, port);
     67 	const family = match (addr) {
     68 	case ip::addr4 =>
     69 		yield rt::AF_INET: int;
     70 	case ip::addr6 =>
     71 		yield rt::AF_INET6: int;
     72 	};
     73 	let f = 0i;
     74 	for (let i = 0z; i < len(options); i += 1) {
     75 		match (options[i]) {
     76 		case let fl: net::sockflag =>
     77 			f |= fl;
     78 		case => void;
     79 		};
     80 	};
     81 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     82 	const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) {
     83 	case let err: rt::errno =>
     84 		return errors::errno(err);
     85 	case let fd: int =>
     86 		yield fd;
     87 	};
     88 
     89 	let bk: u32 = 10;
     90 	for (let i = 0z; i < len(options); i += 1) {
     91 		match (options[i]) {
     92 		case reuseaddr =>
     93 			setsockopt(sockfd, rt::SO_REUSEADDR, true)?;
     94 		case reuseport =>
     95 			setsockopt(sockfd, rt::SO_REUSEPORT, true)?;
     96 		case keepalive =>
     97 			setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
     98 		case let b: backlog =>
     99 			bk = b;
    100 		case => void;
    101 		};
    102 	};
    103 
    104 	const sz = ip::native_addrlen(addr);
    105 	match (rt::bind(sockfd, &sockaddr, sz)) {
    106 	case let err: rt::errno =>
    107 		return errors::errno(err);
    108 	case int => void;
    109 	};
    110 	match (rt::listen(sockfd, bk)) {
    111 	case let err: rt::errno =>
    112 		return errors::errno(err);
    113 	case int => void;
    114 	};
    115 
    116 	for (let i = 0z; i < len(options); i += 1) {
    117 		let portout = match (options[i]) {
    118 		case let p: portassignment =>
    119 			yield p;
    120 		case =>
    121 			continue;
    122 		};
    123 		let sn = rt::sockaddr {...};
    124 		let al = size(rt::sockaddr): u32;
    125 		match (rt::getsockname(sockfd, &sn, &al)) {
    126 		case let err: rt::errno =>
    127 			return errors::errno(err);
    128 		case int => void;
    129 		};
    130 		const addr = ip::from_native(sn);
    131 		*portout = addr.1;
    132 	};
    133 
    134 	return sockfd;
    135 };
    136 
    137 // Returns the remote address for a given connection, or void if none is
    138 // available.
    139 export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = {
    140 	let sn = rt::sockaddr {...};
    141 	let sz = size(rt::sockaddr): u32;
    142 	if (rt::getpeername(peer, &sn, &sz) is rt::errno) {
    143 		return;
    144 	};
    145 	return ip::from_native(sn);
    146 };
    147 
    148 fn setsockopt(
    149 	sockfd: int,
    150 	option: int,
    151 	value: bool,
    152 ) (void | net::error) = {
    153 	let val: int = if (value) 1 else 0;
    154 	match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
    155 			&val: *opaque, size(int): u32)) {
    156 	case let err: rt::errno =>
    157 		return errors::errno(err);
    158 	case int => void;
    159 	};
    160 };