frame(l)                        BEGEMOT Library                       frame(l)

       frame - simple message protocol for byte streams

       # include <begemot.h>

       int frame_write(int fd, void *hdr, u_int hdr_len,
            void *arg...)

       int frame_writev(int fd, void *hdr, u_int hdr_len,
            struct iovec *vec, u_int veclen)

       int frame_read(int fd, void *hdr, u_int hdr_len,
            void **parg, u_int *plen)

       int framefd_write(int fd, void *hdr, u_int hdr_len,
            void *arg...)

       int framefd_writev(int fd, void *hdr, u_int hdr_len,
            struct iovec *vec, u_int veclen)

       int frame_read(int fd, void *hdr, u_int hdr_len,
            void **parg, u_int *plen)

       Most reliable protocols available on UNIX systems are byte stream
       protocols. On the other hand there are many cases, where you need to
       transfer messages. A simple way to do this is to prepend the message
       length to the message and transfer it on the byte stream. The frame_*
       functions are designed to simplify this task for most cases.  They
       assume, that you want to transfer messages, which consist of a fixed
       length header and a variable length part. The fixed header consists of
       at least four bytes, which contain the variable parts length in network
       byte order. For the framefd_* functions the header consists of 8 bytes:
       4 bytes for the length and 4 bytes for a file descriptor. Of course,
       the fixed header can be longer than this minimum.

       There are two pairs of functions. The first pair frame_read and
       frame_write can be used on any reliable byte stream (pipes, UNIX domain
       sockets, TCP sockets, ...). The framefd_read and framefd_write
       functions are specifically designed for UNIX domain sockets --
       additionally to messages they allow the optional transfer of a file
       descriptor with each message.

       The parameter fd is the file descriptor on which the transfer should
       take place.  hdr is a pointer to the fixed size header, which is of
       size hdr_len.  hdr_len must be either 4 or 8 bytes minimum.  The first
       four bytes are set to the length of the variable part in the write
       functions and contain the length of this part if the read functions
       return. The second four bytes of the header must contain the file
       descriptor or -1 for the framefd_write function.  It will contain the
       received file descriptor, -1 if there was no file descriptor or -2, if
       the writing side indicated, that it will send a file descriptor, but
       did not send one. The latter indicates an error in the protocol. A file
       descriptor, that is received, but not expected is closed.

       arg is the start of a variable argument list. This list should consist
       of pairs of void * pointers and u_int sizes, each pair describing a
       piece of the variable message part. The list must be terminated by a
       NULL pointer. If no variable part is to be transmitted, the first
       pointer should simply be NULL.

       parg on the other hand should point to a pointer which points to a
       buffer for the variable length part. The size of the buffer is
       indicated by the number pointed to by plen.  If the indicated buffer
       size is too small for the received message's variable part it will be
       reallocated by calling xrealloc(l).  The actual length of the variable
       part is indicated in the first four bytes of the header.  This
       mechanism tries to minimize buffer allocations and reallocations.
       There is no need to reallocate anything once you got the biggest

       An example on how to use the functions can be found at the end of

       The functions with the v suffix take a pointer to a struct iovec and an
       associated length instead of a variable argument list.  To use these
       functions you need to

       # include <sys/uio.h>

       The write functions return the return value of the corresponding system
       call. Look under sendmsg(2) and writev(2).

       If frame_read is unable to receive the fixed size header, or the header
       is too small, it returns the value from the recvmsg(2) or readv(2)
       system call.  If the corresponding call for the variable part returns
       an error or EOF, the system call's value is returned (0 or -1). If the
       calls for both the header and the variable part are ok, the sum of the
       sizes of both received parts is returned. This means, that you should
       check, that the value returned from the read functions is equal to the
       sum of hdr_len and the first four bytes of the header.

       sendmsg(2),writev(2) recvmsg(2),readv(2)

       The FreeBSD kernel crashes, if you use framefd_write on the writing
       side and frame_read on the reading side. The crash occures in so_flush
       in both the 2.X and 3.0 kernels.

       You cannot transfer file descriptors over pipes in FreeBSD 3.0 anymore,
       because the pipe implementation is not based on socketpair(2) as it was
       the case in all earlier BSDs.

       Due to a bug in the Solaris 2.5 socket emulation it is not possible to
       mix framefd_write with frame_read.

       The write functions impose a limit on the length of the argument list
       and the uio vector. This limit is defined in frame.c and is currently
       defined to be 100.

       Hartmut Brandt,

BEGEMOT                           8 Feb 1998                          frame(l)