NAME
Protocol::Imsg - the OpenBSD imsg(3) frame, as bytes
SYNOPSIS
use Protocol::Imsg;
my $codec = Protocol::Imsg->new;
my $bytes = $codec->encode(type => 8, data => $payload);
$codec->append($received_bytes);
while (my $msg = $codec->next_message) {
# $msg->{type}, $msg->{peerid}, $msg->{pid}, $msg->{data}
}
DESCRIPTION
This module frames and unframes messages of the OpenBSD imsg(3) facility. It takes bytes and returns bytes: it performs no system call, it opens no file, and it names no socket. Fugu::Imsg owns the socket and uses this module for the frame.
State three limits before anything else, because each one bounds where this module is usable.
- The header is native-endian, and the format never crosses a host.
-
Both ends of an imsg connection are the same machine, so imsg writes the header in the sender's own byte order. There is no byte-order negotiation and no network-order variant. Two hosts that disagree on byte order cannot exchange these frames.
- The module frames without descriptor passing.
-
Native imsg can pass a file descriptor as
SCM_RIGHTSancillary data, on a message whoselencarriesIMSG_FD_MARK. This module masks that mark off and never sets it, so it reads such a message as a plain frame and it can never send one. A caller that needs descriptor passing needsrecvmsgandsendmsgas well, which this codec has no way to reach. encodereads$$on every call.-
Native imsg seeds the pid once, when the buffer is initialized. This module reads it per call instead. The two agree in one process and diverge in a forked child: the child's frames carry the child's pid where native imsg would still carry the parent's. Pass
pidexplicitly when that matters.
The wire format is in spec/MDNS-Imsg.md in this repository. That document is a curated reference, not an installed manual.
CONSTANTS
HEADER_SIZE-
16, the size of
struct imsg_hdr. HEADER_TEMPLATE-
The
packtemplate of the header:L4, four nativeuint32fields in the ordertype,len,peerid,pid. MAX_IMSGSIZE-
16384, the bound on the whole message.
MAX_PAYLOAD-
16368, which is
MAX_IMSGSIZEless the header. FD_MARK-
0x80000000, the reserved high bit oflen.
METHODS
new()
Return a codec with an empty decode buffer.
encode(%args)
Return the framed bytes of one message.
type-
The message type. Required.
data-
The payload. The default is the empty string.
peerid-
A correlation value that is opaque to this module. The default is 0, which is what a protocol that does not correlate sends.
pid-
The sender pid. The default is
$$. Apidof 0 also gives$$, because imsg substitutes the sender's pid for a 0 the caller passes.
The method returns undef, with $! set to EMSGSIZE, for a payload above MAX_PAYLOAD. An encoder must refuse a larger payload rather than truncate it.
append($bytes)
Add received bytes to the decode buffer and return the object. A partial header, a partial payload, and several whole messages at once are all normal.
next_message()
Pop one whole message off the buffer and return a hash reference with type, peerid, pid, and data. Return undef when more bytes are necessary.
An invalid len sets $! to EBADMSG and makes the failure permanent: native imsg drops such a connection, and so must every reader. len is invalid below HEADER_SIZE and above MAX_IMSGSIZE.
is_failed()
Report the permanent framing failure. Nothing clears it but reset.
reset()
Empty the buffer, clear the failure, and return the object. A transport calls it when it closes a connection, so that a frame which arrived before the close cannot come out after it.
SEE ALSO
Fugu::Imsg, spec/MDNS-Imsg.md