hare

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

+freebsd.ha (2519B)


      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 	const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | 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 sz = size(rt::sockaddr_un): u32;
     36 	match (rt::connect(sockfd, &sockaddr, sz)) {
     37 	case let err: rt::errno =>
     38 		return errors::errno(err);
     39 	case int => void;
     40 	};
     41 	return io::fdopen(sockfd);
     42 };
     43 
     44 // Binds a UNIX socket to the given path.
     45 export fn listen(
     46 	addr: addr,
     47 	options: listen_option...
     48 ) (net::socket | net::error) = {
     49 	let sockaddr = match (to_native(addr)) {
     50 	case let a: rt::sockaddr =>
     51 		yield a;
     52 	case invalid =>
     53 		return errors::unsupported; // path too long
     54 	};
     55 	let f = 0i;
     56 	for (let i = 0z; i < len(options); i += 1) {
     57 		match (options[i]) {
     58 		case let fl: net::sockflag =>
     59 			f |= fl;
     60 		case => void;
     61 		};
     62 	};
     63 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     64 	const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
     65 	case let err: rt::errno =>
     66 		return errors::errno(err);
     67 	case let fd: int =>
     68 		yield fd;
     69 	};
     70 
     71 	let bk: u32 = 10;
     72 	for (let i = 0z; i < len(options); i += 1) {
     73 		match (options[i]) {
     74 		case let b: backlog =>
     75 			bk = b;
     76 		case => void;
     77 		};
     78 	};
     79 
     80 	match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
     81 	case let err: rt::errno =>
     82 		return errors::errno(err);
     83 	case int => void;
     84 	};
     85 	match (rt::listen(sockfd, bk)) {
     86 	case let err: rt::errno =>
     87 		return errors::errno(err);
     88 	case int => void;
     89 	};
     90 
     91 	return sockfd;
     92 };
     93 
     94 // Converts a UNIX socket address to a native sockaddr.
     95 fn to_native(addr: addr) (rt::sockaddr | invalid) = {
     96 	// sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX
     97 	if (len(addr) > rt::UNIX_PATH_MAX - 1) {
     98 		return invalid;
     99 	};
    100 	let ret = rt::sockaddr {
    101 		un = rt::sockaddr_un {
    102 			sun_len = size(rt::sockaddr_un): u8,
    103 			sun_family = rt::AF_UNIX,
    104 			...
    105 		}
    106 	};
    107 	c::fromstr_buf(addr, ret.un.sun_path: []c::char);
    108 	return ret;
    109 };