hare

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

msg.ha (3889B)


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