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