hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

+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 };