hare

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

msg.ha (3896B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 // TODO:
      5 // - Set name field
      6 // - Figure out the portability mess that is this interface
      7 use fmt;
      8 use rt;
      9 
     10 export type msghdr = struct {
     11 	native: rt::msghdr,
     12 	vectors: []rt::iovec,
     13 	control: []u8,
     14 };
     15 
     16 // Creates a new message header for advanced socket usage, with configurable I/O
     17 // vectors, control messages, and other details, for use with [[sendmsg]] and
     18 // [[recvmsg]].
     19 //
     20 // The user must call [[finish]] when they are done using this message for
     21 // sending or receiving. The same message may be used for multiple operations
     22 // before calling [[finish]]. [[reset]] may be used to "reset" a [[msghdr]] to
     23 // an empty list of I/O vectors and control messages without freeing the
     24 // underlying memory, which may be useful if future messages are expected to
     25 // have similar characteristics.
     26 export fn newmsg() msghdr = msghdr { ... };
     27 
     28 // Frees resources associated with a [[msghdr]].
     29 export fn finish(msg: *msghdr) void = {
     30 	free(msg.control);
     31 	free(msg.vectors);
     32 };
     33 
     34 // Resets a message header, clearing out any I/O vectors or control messages,
     35 // without freeing the underlying memory. This allows the user to configure new
     36 // vectors or control messages without a re-allocation, which improves
     37 // performance if the new configuration fits into the same amount of memory.
     38 export fn reset(msg: *msghdr) void = {
     39 	msg.control = msg.control[..0];
     40 	msg.vectors = msg.vectors[..0];
     41 };
     42 
     43 // Adds an I/O vector to the message.
     44 export fn addvector(msg: *msghdr, vec: []u8) void = {
     45 	append(msg.vectors, rt::iovec {
     46 		iov_base = vec: *[*]u8,
     47 		iov_len = len(vec),
     48 	});
     49 };
     50 
     51 // Sets flags for this message.
     52 export fn setflags(msg: *msghdr, flags: int) void = {
     53 	msg.native.msg_flags = flags;
     54 };
     55 
     56 // Get flags for this message.
     57 export fn getflags(msg: *msghdr) int = {
     58 	return msg.native.msg_flags;
     59 };
     60 
     61 // Sets name for this message.
     62 export fn setname(msg: *msghdr, name: *opaque, length: size) void = {
     63 	msg.native.msg_name = name;
     64 	msg.native.msg_namelen = length: u32;
     65 };
     66 
     67 // Adds a control message of the desired length to a [[msghdr]], returning a
     68 // buffer in which the ancillary data may be written in a domain-specific
     69 // format.
     70 //
     71 // This is a low-level interface, and is not generally used by users. More
     72 // often, users will call functions like [[net::unix::addfiles]] or
     73 // [[net::unix::allocfiles]], which provide a high-level interface to this
     74 // function for domain-specific use-cases.
     75 export fn addcontrol(
     76 	msg: *msghdr,
     77 	length: size,
     78 	level: int,
     79 	ctype: int,
     80 ) []u8 = {
     81 	const prev = len(msg.control);
     82 	const space = cmsg_space(length);
     83 	append(msg.control, [0...], space);
     84 	let newbuf = msg.control[prev..prev + space]: *[*]rt::cmsghdr;
     85 	newbuf[0].cmsg_len = cmsg_len(length): uint;
     86 	newbuf[0].cmsg_level = level;
     87 	newbuf[0].cmsg_type = ctype;
     88 	let user = &newbuf[1]: *[*]u8;
     89 	return user[..length];
     90 };
     91 
     92 // Retrieves a control header from a message, returning a slice of
     93 // domain-specific data.
     94 //
     95 // This is a low-level interface, and is not generally used by users. More
     96 // often, users will call functions like [[net::unix::addfiles]] or
     97 // [[net::unix::allocfiles]], which provide a high-level interface to this
     98 // function for domain-specific use-cases.
     99 export fn getcontrol(
    100 	msg: *msghdr,
    101 	length: size,
    102 	level: int,
    103 	ctype: int,
    104 ) ([]u8 | void) = {
    105 	let native = &msg.native;
    106 	let cbuf = native.msg_control: *[*]u8;
    107 	for (let i = 0z; i < native.msg_controllen) {
    108 		let next = &cbuf[i]: *rt::cmsg;
    109 		if (next.hdr.cmsg_len >= length
    110 				&& next.hdr.cmsg_level == level
    111 				&& next.hdr.cmsg_type == ctype) {
    112 			return next.cmsg_data[..length];
    113 		};
    114 		i += next.hdr.cmsg_len;
    115 	};
    116 };
    117 
    118 fn cmsg_align(z: size) size = (z + size(size) - 1) & ~(size(size) - 1);
    119 fn cmsg_len(z: size) size = cmsg_align(size(rt::cmsghdr)) + z;
    120 fn cmsg_space(z: size) size = cmsg_align(size(rt::cmsghdr)) + cmsg_align(z);