+openbsd.ha (2538B)
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 flags = 0i; 23 for (let i = 0z; i < len(options); i += 1) { 24 // Only sockflag for now 25 flags |= options[i]; 26 }; 27 flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 28 const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | flags, 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 void => 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 void => void; 84 }; 85 match (rt::listen(sockfd, bk)) { 86 case let err: rt::errno => 87 return errors::errno(err); 88 case void => 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 };