+openbsd.ha (2942B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use errors; 5 use io; 6 use rt; 7 8 // A network socket. 9 export type socket = io::file; 10 11 // Optional flags to [[accept]] to be set on the returned [[socket]]. 12 // See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. 13 // Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. 14 export type sockflag = enum int { 15 NOCLOEXEC = rt::SOCK_CLOEXEC, 16 NONBLOCK = rt::SOCK_NONBLOCK 17 }; 18 19 // Accepts the next connection from a socket. Blocks until a new connection is 20 // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are 21 // supplied, the [[io::file]] returned will have the supplied flags set. 22 export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { 23 flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC 24 const fd = match (rt::accept4(sock, null, null, flags)) { 25 case let err: rt::errno => 26 return errors::errno(err); 27 case let fd: int => 28 yield fd; 29 }; 30 return io::fdopen(fd); 31 }; 32 33 fn msg_to_native(msg: *msghdr) *rt::msghdr = { 34 let native = &msg.native; 35 if (len(msg.vectors) != 0) { 36 native.msg_iov = msg.vectors: *[*]rt::iovec; 37 // XXX: size -> uint could overflow here. 38 native.msg_iovlen = len(msg.vectors): uint; 39 }; 40 if (len(msg.control) != 0) { 41 native.msg_control = msg.control: *[*]u8; 42 // XXX: size -> uint could overflow here. 43 native.msg_controllen = len(msg.control): uint; 44 }; 45 return native; 46 }; 47 48 // Sends a message to a socket. See [[newmsg]] for details. 49 export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { 50 // TODO: Flags 51 match (rt::sendmsg(sock, msg_to_native(msg), 0)) { 52 case let n: int => 53 return n: size; 54 case let err: rt::errno => 55 return errors::errno(err); 56 }; 57 }; 58 59 // Receives a message from a socket. See [[newmsg]] for details. 60 export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { 61 // TODO: Flags 62 match (rt::recvmsg(sock, msg_to_native(msg), 0)) { 63 case let n: int => 64 return n: size; 65 case let err: rt::errno => 66 return errors::errno(err); 67 }; 68 }; 69 70 // Closes a [[socket]]. No further operations against this socket are permitted 71 // after calling this function. Closing a socket can fail only under certain 72 // conditions (for example, closing a socket twice, or an interrupted syscall). 73 // However, the user should not attempt to close the file again on failure - at 74 // best the user should print a diagnostic message and move on. See close(2) for 75 // details. 76 // 77 // On OpenBSD, this function is an alias for [[io::close]]. 78 export fn close(sock: socket) (void | error) = match (io::close(sock)) { 79 case void => void; 80 case io::underread => abort(); 81 case io::mode => abort(); 82 case let err: errors::error => 83 yield err; 84 }; 85 86 // Shuts down part of a full-duplex connection. 87 export fn shutdown(sock: socket, how: shut) (void | error) = { 88 match (rt::shutdown(sock, how)) { 89 case void => void; 90 case let err: rt::errno => 91 return errors::errno(err); 92 }; 93 };