+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 };