hare

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

+freebsd.ha (2670B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use errors;
      5 use fmt;
      6 use io;
      7 use net;
      8 use os;
      9 use rt;
     10 use strings;
     11 use types;
     12 
     13 // Opens a UNIX socket connection to the path. Blocks until the connection is
     14 // established.
     15 export fn connect(
     16 	addr: addr,
     17 	options: connect_option...
     18 ) (net::socket | net::error) = {
     19 	let sockaddr = match (to_native(addr)) {
     20 	case let a: rt::sockaddr =>
     21 		yield a;
     22 	case invalid =>
     23 		return errors::unsupported; // path too long
     24 	};
     25 	let f = 0i;
     26 	for (let i = 0z; i < len(options); i += 1) {
     27 		// Only sockflag for now
     28 		f |= options[i];
     29 	};
     30 	f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC
     31 	const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
     32 	case let err: rt::errno =>
     33 		return errors::errno(err);
     34 	case let fd: int =>
     35 		yield fd;
     36 	};
     37 
     38 	const sz = size(rt::sockaddr_un): u32;
     39 	match (rt::connect(sockfd, &sockaddr, sz)) {
     40 	case let err: rt::errno =>
     41 		return errors::errno(err);
     42 	case int => void;
     43 	};
     44 	return io::fdopen(sockfd);
     45 };
     46 
     47 // Binds a UNIX socket to the given path.
     48 export fn listen(
     49 	addr: addr,
     50 	options: listen_option...
     51 ) (net::socket | net::error) = {
     52 	let sockaddr = match (to_native(addr)) {
     53 	case let a: rt::sockaddr =>
     54 		yield a;
     55 	case invalid =>
     56 		return errors::unsupported; // path too long
     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(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) {
     68 	case let err: rt::errno =>
     69 		return errors::errno(err);
     70 	case let fd: int =>
     71 		yield fd;
     72 	};
     73 
     74 	let bk: u32 = 10;
     75 	for (let i = 0z; i < len(options); i += 1) {
     76 		match (options[i]) {
     77 		case let b: backlog =>
     78 			bk = b;
     79 		case => void;
     80 		};
     81 	};
     82 
     83 	match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
     84 	case let err: rt::errno =>
     85 		return errors::errno(err);
     86 	case int => void;
     87 	};
     88 	match (rt::listen(sockfd, bk)) {
     89 	case let err: rt::errno =>
     90 		return errors::errno(err);
     91 	case int => void;
     92 	};
     93 
     94 	return sockfd;
     95 };
     96 
     97 // Converts a UNIX socket address to a native sockaddr.
     98 fn to_native(addr: addr) (rt::sockaddr | invalid) = {
     99 	// sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX
    100 	if (len(addr) > rt::UNIX_PATH_MAX - 1) {
    101 		return invalid;
    102 	};
    103 	let ret = rt::sockaddr {
    104 		un = rt::sockaddr_un {
    105 			sun_len = size(rt::sockaddr_un): u8,
    106 			sun_family = rt::AF_UNIX,
    107 			...
    108 		}
    109 	};
    110 	match ((&addr: *types::string).data) {
    111 	case null => void;
    112 	case let data: *[*]u8 =>
    113 		ret.un.sun_path[..len(addr)] = data[..len(addr)];
    114 	};
    115 	ret.un.sun_path[len(addr)] = 0;
    116 	return ret;
    117 };