hare

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

+linux.ha (4470B)


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