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