+openbsd.ha (4528B)
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 // Creates a UDP socket and sets the default destination to the given address. 11 export fn connect( 12 dest: ip::addr, 13 port: u16, 14 options: connect_option... 15 ) (net::socket | net::error) = { 16 const family = match (dest) { 17 case ip::addr4 => 18 yield rt::AF_INET: int; 19 case ip::addr6 => 20 yield rt::AF_INET6: int; 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(family, rt::SOCK_DGRAM | 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 sockaddr = ip::to_native(dest, port); 36 const sz = ip::native_addrlen(dest); 37 match (rt::connect(sockfd, &sockaddr, sz)) { 38 case void => 39 return io::fdopen(sockfd); 40 case let err: rt::errno => 41 return errors::errno(err); 42 }; 43 }; 44 45 // Creates a UDP socket bound to an interface. 46 export fn listen( 47 addr: ip::addr, 48 port: u16, 49 options: listen_option... 50 ) (net::socket | net::error) = { 51 const family = match (addr) { 52 case ip::addr4 => 53 yield rt::AF_INET: int; 54 case ip::addr6 => 55 yield rt::AF_INET6: int; 56 }; 57 let flags = 0i; 58 for (let i = 0z; i < len(options); i += 1) { 59 match (options[i]) { 60 case let fl: net::sockflag => 61 flags |= fl; 62 case => void; 63 }; 64 }; 65 flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC 66 const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | flags, 0)) { 67 case let err: rt::errno => 68 return errors::errno(err); 69 case let fd: int => 70 yield fd; 71 }; 72 73 for (let i = 0z; i < len(options); i += 1) { 74 match (options[i]) { 75 case reuseaddr => 76 setsockopt(sockfd, rt::SO_REUSEADDR, true)?; 77 case reuseport => 78 setsockopt(sockfd, rt::SO_REUSEPORT, true)?; 79 case => void; 80 }; 81 }; 82 83 const sockaddr = ip::to_native(addr, port); 84 const sz = ip::native_addrlen(addr); 85 match (rt::bind(sockfd, &sockaddr, sz)) { 86 case void => void; 87 case let err: rt::errno => 88 return errors::errno(err); 89 }; 90 91 for (let i = 0z; i < len(options); i += 1) { 92 let portout = match (options[i]) { 93 case let p: portassignment => 94 yield p; 95 case => 96 continue; 97 }; 98 let sn = rt::sockaddr {...}; 99 let al = size(rt::sockaddr): u32; 100 match (rt::getsockname(sockfd, &sn, &al)) { 101 case let err: rt::errno => 102 return errors::errno(err); 103 case void => void; 104 }; 105 const addr = ip::from_native(sn); 106 *portout = addr.1; 107 }; 108 109 return io::fdopen(sockfd); 110 }; 111 112 // Sends a UDP packet to a [[connect]]ed UDP socket. 113 export fn send(sock: net::socket, buf: []u8) (size | net::error) = { 114 match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, null, 0)) { 115 case let sz: size => 116 return sz; 117 case let err: rt::errno => 118 return errors::errno(err); 119 }; 120 }; 121 122 // Sends a UDP packet using this socket. 123 export fn sendto( 124 sock: net::socket, 125 buf: []u8, 126 dest: ip::addr, 127 port: u16, 128 ) (size | net::error) = { 129 const sockaddr = ip::to_native(dest, port); 130 const sz = ip::native_addrlen(dest); 131 match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { 132 case let sz: size => 133 return sz; 134 case let err: rt::errno => 135 return errors::errno(err); 136 }; 137 }; 138 139 // Receives a UDP packet from a [[connect]]ed UDP socket. 140 export fn recv( 141 sock: net::socket, 142 buf: []u8, 143 ) (size | net::error) = { 144 match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, null, null)) { 145 case let sz: size => 146 return sz; 147 case let err: rt::errno => 148 return errors::errno(err); 149 }; 150 }; 151 152 // Receives a UDP packet from a bound socket. 153 export fn recvfrom( 154 sock: net::socket, 155 buf: []u8, 156 src: nullable *ip::addr, 157 port: nullable *u16, 158 ) (size | net::error) = { 159 let addrsz = size(rt::sockaddr): u32; 160 const sockaddr = rt::sockaddr { ... }; 161 const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, 162 &sockaddr, &addrsz)) { 163 case let sz: size => 164 yield sz; 165 case let err: rt::errno => 166 return errors::errno(err); 167 }; 168 169 assert(addrsz <= size(rt::sockaddr)); 170 const peer = ip::from_native(sockaddr); 171 match (src) { 172 case null => void; 173 case let src: *ip::addr => 174 *src = peer.0; 175 }; 176 match (port) { 177 case null => void; 178 case let port: *u16 => 179 *port = peer.1; 180 }; 181 182 return sz; 183 }; 184 185 fn setsockopt( 186 sockfd: int, 187 option: int, 188 value: bool, 189 ) (void | net::error) = { 190 let val: int = if (value) 1 else 0; 191 match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, 192 &val: *opaque, size(int): u32)) { 193 case let err: rt::errno => 194 return errors::errno(err); 195 case void => void; 196 }; 197 };