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