+freebsd.ha (3676B)
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 net::ip; 8 use rt; 9 10 // Opens a TCP connection to the given host and port. Blocks until the 11 // connection is established. 12 export fn connect( 13 addr: ip::addr, 14 port: u16, 15 options: connect_option... 16 ) (net::socket | net::error) = { 17 const sockaddr = ip::to_native(addr, port); 18 const family = match (addr) { 19 case ip::addr4 => 20 yield rt::AF_INET: int; 21 case ip::addr6 => 22 yield rt::AF_INET6: int; 23 }; 24 let f = 0i; 25 for (let i = 0z; i < len(options); i += 1) { 26 match (options[i]) { 27 case let fl: net::sockflag => 28 f |= fl; 29 case => void; 30 }; 31 }; 32 f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 33 const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { 34 case let err: rt::errno => 35 return errors::errno(err); 36 case let fd: int => 37 yield fd; 38 }; 39 40 for (let i = 0z; i < len(options); i += 1) { 41 match (options[i]) { 42 case keepalive => 43 setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; 44 case => void; 45 }; 46 }; 47 const sz = ip::native_addrlen(addr); 48 match (rt::connect(sockfd, &sockaddr, sz)) { 49 case let err: rt::errno => 50 if (err != rt::EINPROGRESS) { 51 return errors::errno(err); 52 }; 53 assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK); 54 case int => void; 55 }; 56 return io::fdopen(sockfd); 57 }; 58 59 // Binds a TCP socket to the given address. 60 export fn listen( 61 addr: ip::addr, 62 port: u16, 63 options: listen_option... 64 ) (net::socket | net::error) = { 65 const sockaddr = ip::to_native(addr, port); 66 const family = match (addr) { 67 case ip::addr4 => 68 yield rt::AF_INET: int; 69 case ip::addr6 => 70 yield rt::AF_INET6: int; 71 }; 72 let f = 0i; 73 for (let i = 0z; i < len(options); i += 1) { 74 match (options[i]) { 75 case let fl: net::sockflag => 76 f |= fl; 77 case => void; 78 }; 79 }; 80 f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 81 const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { 82 case let err: rt::errno => 83 return errors::errno(err); 84 case let fd: int => 85 yield fd; 86 }; 87 88 let bk: u32 = 10; 89 for (let i = 0z; i < len(options); i += 1) { 90 match (options[i]) { 91 case reuseaddr => 92 setsockopt(sockfd, rt::SO_REUSEADDR, true)?; 93 case reuseport => 94 setsockopt(sockfd, rt::SO_REUSEPORT, true)?; 95 case keepalive => 96 setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; 97 case let b: backlog => 98 bk = b; 99 case => void; 100 }; 101 }; 102 103 const sz = ip::native_addrlen(addr); 104 match (rt::bind(sockfd, &sockaddr, sz)) { 105 case let err: rt::errno => 106 return errors::errno(err); 107 case int => void; 108 }; 109 match (rt::listen(sockfd, bk)) { 110 case let err: rt::errno => 111 return errors::errno(err); 112 case int => void; 113 }; 114 115 for (let i = 0z; i < len(options); i += 1) { 116 let portout = match (options[i]) { 117 case let p: portassignment => 118 yield p; 119 case => 120 continue; 121 }; 122 let sn = rt::sockaddr {...}; 123 let al = size(rt::sockaddr): u32; 124 match (rt::getsockname(sockfd, &sn, &al)) { 125 case let err: rt::errno => 126 return errors::errno(err); 127 case int => void; 128 }; 129 const addr = ip::from_native(sn); 130 *portout = addr.1; 131 }; 132 133 return sockfd; 134 }; 135 136 // Returns the remote address for a given connection, or void if none is 137 // available. 138 export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { 139 let sn = rt::sockaddr {...}; 140 let sz = size(rt::sockaddr): u32; 141 if (rt::getpeername(peer, &sn, &sz) is rt::errno) { 142 return; 143 }; 144 return ip::from_native(sn); 145 }; 146 147 fn setsockopt( 148 sockfd: int, 149 option: int, 150 value: bool, 151 ) (void | net::error) = { 152 let val: int = if (value) 1 else 0; 153 match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, 154 &val: *opaque, size(int): u32)) { 155 case let err: rt::errno => 156 return errors::errno(err); 157 case int => void; 158 }; 159 };