+linux.ha (2840B)
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 DGRAM = rt::SOCK_DGRAM, 18 }; 19 20 // Accepts the next connection from a socket. Blocks until a new connection is 21 // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are 22 // supplied, the [[io::file]] returned will have the supplied flags set. 23 export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { 24 flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC 25 const fd = match (rt::accept4(sock, null, null, flags)) { 26 case let err: rt::errno => 27 return errors::errno(err); 28 case let fd: int => 29 yield fd; 30 }; 31 return io::fdopen(fd); 32 }; 33 34 fn msg_to_native(msg: *msghdr) *rt::msghdr = { 35 let native = &msg.native; 36 if (len(msg.vectors) != 0) { 37 native.msg_iov = msg.vectors: *[*]rt::iovec; 38 native.msg_iovlen = len(msg.vectors); 39 }; 40 if (len(msg.control) != 0) { 41 native.msg_control = msg.control: *[*]u8; 42 native.msg_controllen = len(msg.control); 43 }; 44 return native; 45 }; 46 47 // Sends a message to a socket. See [[newmsg]] for details. 48 export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { 49 // TODO: Flags 50 match (rt::sendmsg(sock, msg_to_native(msg), 0)) { 51 case let n: int => 52 return n: size; 53 case let err: rt::errno => 54 return errors::errno(err); 55 }; 56 }; 57 58 // Receives a message from a socket. See [[newmsg]] for details. 59 export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { 60 // TODO: Flags 61 match (rt::recvmsg(sock, msg_to_native(msg), 0)) { 62 case let n: int => 63 return n: size; 64 case let err: rt::errno => 65 return errors::errno(err); 66 }; 67 }; 68 69 // Closes a [[socket]]. No further operations against this socket are permitted 70 // after calling this function. Closing a socket can fail only under certain 71 // conditions (for example, closing a socket twice, or an interrupted syscall). 72 // However, the user should not attempt to close the file again on failure - at 73 // best the user should print a diagnostic message and move on. See close(2) for 74 // details. 75 // 76 // On Linux, this function is an alias for [[io::close]]. 77 export fn close(sock: socket) (void | error) = match (io::close(sock)) { 78 case void => void; 79 case io::underread => abort(); 80 case let err: errors::error => 81 yield err; 82 }; 83 84 // Shuts down part of a full-duplex connection. 85 export fn shutdown(sock: socket, how: shut) (void | error) = { 86 match (rt::shutdown(sock, how)) { 87 case void => void; 88 case let err: rt::errno => 89 return errors::errno(err); 90 }; 91 };