hare

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

+netbsd.ha (4465B)


      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 rt;
      9 
     10 // Creates a UDP socket and sets the default destination to the given address.
     11 export fn connect(
     12 	dest: ip::addr,
     13 	port: u16,
     14 	options: connect_option...
     15 ) (net::socket | net::error) = {
     16 	const family = match (dest) {
     17 	case ip::addr4 =>
     18 		yield rt::AF_INET: int;
     19 	case ip::addr6 =>
     20 		yield rt::AF_INET6: int;
     21 	};
     22 	let f = 0i;
     23 	for (let i = 0z; i < len(options); i += 1) {
     24 		// Only sockflag for now
     25 		f |= options[i];
     26 	};
     27 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     28 	const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
     29 	case let err: rt::errno =>
     30 		return errors::errno(err);
     31 	case let fd: int =>
     32 		yield fd;
     33 	};
     34 
     35 	const sockaddr = ip::to_native(dest, port);
     36 	const sz = ip::native_addrlen(dest);
     37 	match (rt::connect(sockfd, &sockaddr, sz)) {
     38 	case int =>
     39 		return io::fdopen(sockfd);
     40 	case let err: rt::errno =>
     41 		return errors::errno(err);
     42 	};
     43 };
     44 
     45 // Creates a UDP socket bound to an interface.
     46 export fn listen(
     47 	addr: ip::addr,
     48 	port: u16,
     49 	options: listen_option...
     50 ) (net::socket | net::error) = {
     51 	const family = match (addr) {
     52 	case ip::addr4 =>
     53 		yield rt::AF_INET: int;
     54 	case ip::addr6 =>
     55 		yield rt::AF_INET6: int;
     56 	};
     57 	let f = 0i;
     58 	for (let i = 0z; i < len(options); i += 1) {
     59 		match (options[i]) {
     60 		case let fl: net::sockflag =>
     61 			f |= fl;
     62 		case => void;
     63 		};
     64 	};
     65 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     66 	const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) {
     67 	case let err: rt::errno =>
     68 		return errors::errno(err);
     69 	case let fd: int =>
     70 		yield fd;
     71 	};
     72 
     73 	for (let i = 0z; i < len(options); i += 1) {
     74 		match (options[i]) {
     75 		case reuseaddr =>
     76 			setsockopt(sockfd, rt::SO_REUSEADDR, true)?;
     77 		case reuseport =>
     78 			setsockopt(sockfd, rt::SO_REUSEPORT, true)?;
     79 		case => void;
     80 		};
     81 	};
     82 
     83 	const sockaddr = ip::to_native(addr, port);
     84 	const sz = ip::native_addrlen(addr);
     85 	match (rt::bind(sockfd, &sockaddr, sz)) {
     86 	case int => void;
     87 	case let err: rt::errno =>
     88 		return errors::errno(err);
     89 	};
     90 
     91 	for (let i = 0z; i < len(options); i += 1) {
     92 		let portout = match (options[i]) {
     93 		case let p: portassignment =>
     94 			yield p;
     95 		case =>
     96 			continue;
     97 		};
     98 		let sn = rt::sockaddr {...};
     99 		let al = size(rt::sockaddr): u32;
    100 		match (rt::getsockname(sockfd, &sn, &al)) {
    101 		case let err: rt::errno =>
    102 			return errors::errno(err);
    103 		case int => void;
    104 		};
    105 		const addr = ip::from_native(sn);
    106 		*portout = addr.1;
    107 	};
    108 
    109 	return io::fdopen(sockfd);
    110 };
    111 
    112 // Sends a UDP packet to a [[connect]]ed UDP socket.
    113 export fn send(sock: net::socket, buf: []u8) (size | net::error) = {
    114 	match (rt::send(sock, buf: *[*]u8, len(buf), 0)) {
    115 	case let sz: size =>
    116 		return sz;
    117 	case let err: rt::errno =>
    118 		return errors::errno(err);
    119 	};
    120 };
    121 
    122 // Sends a UDP packet using this socket.
    123 export fn sendto(
    124 	sock: net::socket,
    125 	buf: []u8,
    126 	dest: ip::addr,
    127 	port: u16,
    128 ) (size | net::error) = {
    129 	const sockaddr = ip::to_native(dest, port);
    130 	const sz = ip::native_addrlen(dest);
    131 	match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) {
    132 	case let sz: size =>
    133 		return sz;
    134 	case let err: rt::errno =>
    135 		return errors::errno(err);
    136 	};
    137 };
    138 
    139 // Receives a UDP packet from a [[connect]]ed UDP socket.
    140 export fn recv(
    141 	sock: net::socket,
    142 	buf: []u8,
    143 ) (size | net::error) = {
    144 	match (rt::recv(sock, buf: *[*]u8, len(buf), 0)) {
    145 	case let sz: size =>
    146 		return sz;
    147 	case let err: rt::errno =>
    148 		return errors::errno(err);
    149 	};
    150 };
    151 
    152 // Receives a UDP packet from a bound socket.
    153 export fn recvfrom(
    154 	sock: net::socket,
    155 	buf: []u8,
    156 	src: nullable *ip::addr,
    157 	port: nullable *u16,
    158 ) (size | net::error) = {
    159 	let addrsz = size(rt::sockaddr): u32;
    160 	const sockaddr = rt::sockaddr { ... };
    161 	const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0,
    162 		&sockaddr, &addrsz)) {
    163 	case let sz: size =>
    164 		yield sz;
    165 	case let err: rt::errno =>
    166 		return errors::errno(err);
    167 	};
    168 
    169 	assert(addrsz <= size(rt::sockaddr));
    170 	const peer = ip::from_native(sockaddr);
    171 	match (src) {
    172 	case null => void;
    173 	case let src: *ip::addr =>
    174 		*src = peer.0;
    175 	};
    176 	match (port) {
    177 	case null => void;
    178 	case let port: *u16 =>
    179 		*port = peer.1;
    180 	};
    181 
    182 	return sz;
    183 };
    184 
    185 fn setsockopt(
    186 	sockfd: int,
    187 	option: int,
    188 	value: bool,
    189 ) (void | net::error) = {
    190 	let val: int = if (value) 1 else 0;
    191 	match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
    192 			&val: *opaque, size(int): u32)) {
    193 	case let err: rt::errno =>
    194 		return errors::errno(err);
    195 	case int => void;
    196 	};
    197 };