hare

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

+linux.ha (2653B)


      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 rt;
      8 use types::c;
      9 
     10 // Opens a UNIX socket connection to the path. Blocks until the connection is
     11 // established.
     12 export fn connect(
     13 	addr: addr,
     14 	options: connect_option...
     15 ) (net::socket | net::error) = {
     16 	let sockaddr = match (to_native(addr)) {
     17 	case let a: rt::sockaddr =>
     18 		yield a;
     19 	case invalid =>
     20 		return errors::unsupported; // path too long
     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 
     29 	// set default type if none provided. assumes that socket types will
     30 	// not outgrow 0xf and additional flags will not be added within 0xf.
     31 	if (f & 0xf == 0) {
     32 		f |= rt::SOCK_STREAM;
     33 	};
     34 
     35 	const sockfd = match (rt::socket(rt::AF_UNIX: int, f, 0)) {
     36 	case let err: rt::errno =>
     37 		return errors::errno(err);
     38 	case let fd: int =>
     39 		yield fd;
     40 	};
     41 
     42 	const sz = size(rt::sockaddr_un): u32;
     43 	match (rt::connect(sockfd, &sockaddr, sz)) {
     44 	case let err: rt::errno =>
     45 		return errors::errno(err);
     46 	case int => void;
     47 	};
     48 	return io::fdopen(sockfd);
     49 };
     50 
     51 // Binds a UNIX socket to the given path.
     52 export fn listen(
     53 	addr: addr,
     54 	options: listen_option...
     55 ) (net::socket | net::error) = {
     56 	let sockaddr = match (to_native(addr)) {
     57 	case let a: rt::sockaddr =>
     58 		yield a;
     59 	case invalid =>
     60 		return errors::unsupported; // path too long
     61 	};
     62 	let f = 0i;
     63 	for (let i = 0z; i < len(options); i += 1) {
     64 		match (options[i]) {
     65 		case let fl: net::sockflag =>
     66 			f |= fl;
     67 		case => void;
     68 		};
     69 	};
     70 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     71 	const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
     72 	case let err: rt::errno =>
     73 		return errors::errno(err);
     74 	case let fd: int =>
     75 		yield fd;
     76 	};
     77 
     78 	let bk: u32 = 10;
     79 	for (let i = 0z; i < len(options); i += 1) {
     80 		match (options[i]) {
     81 		case let b: backlog =>
     82 			bk = b;
     83 		case => void;
     84 		};
     85 	};
     86 
     87 	match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
     88 	case let err: rt::errno =>
     89 		return errors::errno(err);
     90 	case int => void;
     91 	};
     92 	match (rt::listen(sockfd, bk)) {
     93 	case let err: rt::errno =>
     94 		return errors::errno(err);
     95 	case int => void;
     96 	};
     97 
     98 	return sockfd;
     99 };
    100 
    101 // Converts a UNIX socket address to a native sockaddr.
    102 fn to_native(addr: addr) (rt::sockaddr | invalid) = {
    103 	// sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX
    104 	if (len(addr) > rt::UNIX_PATH_MAX - 1) {
    105 		return invalid;
    106 	};
    107 	let ret = rt::sockaddr {
    108 		un = rt::sockaddr_un {
    109 			sun_family = rt::AF_UNIX,
    110 			...
    111 		}
    112 	};
    113 	c::fromstr_buf(addr, ret.un.sun_path: []c::char);
    114 	return ret;
    115 };