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