+linux.ha (2630B)
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_family = rt::AF_UNIX, 106 ... 107 } 108 }; 109 match ((&addr: *types::string).data) { 110 case null => void; 111 case let data: *[*]u8 => 112 ret.un.sun_path[..len(addr)] = data[..len(addr)]; 113 }; 114 ret.un.sun_path[len(addr)] = 0; 115 return ret; 116 };