+openbsd.ha (3667B)
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 flags = 0i; 26 for (let i = 0z; i < len(options); i += 1) { 27 match (options[i]) { 28 case let fl: net::sockflag => 29 flags |= fl; 30 case => void; 31 }; 32 }; 33 flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 34 const sockfd = match (rt::socket(family, rt::SOCK_STREAM | flags, 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 case void => 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 flags = 0i; 73 for (let i = 0z; i < len(options); i += 1) { 74 match (options[i]) { 75 case let fl: net::sockflag => 76 flags |= fl; 77 case => void; 78 }; 79 }; 80 flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 81 const sockfd = match (rt::socket(family, rt::SOCK_STREAM | flags, 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 void => void; 108 }; 109 match (rt::listen(sockfd, bk)) { 110 case let err: rt::errno => 111 return errors::errno(err); 112 case void => 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 void => 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 void => void; 158 }; 159 };