+.\" -*-nroff-*-
+.TH pkbuf 3 "16 July 2000" mLib
+.SH "NAME"
+pkbuf \- split packets out of asynchronously received blocks
+.\" @pkbuf_flush
+.\" @pkbuf_close
+.\" @pkbuf_free
+.\" @pkbuf_snarf
+.\" @pkbuf_want
+.\" @pkbuf_init
+.\" @pkbuf_destroy
+.SH "SYNOPSIS"
+.nf
+.B "#include <mLib/pkbuf.h>"
+
+.BI "void pkbuf_flush(pkbuf *" pk ", octet *" p ", size_t " len );
+.BI "void pkbuf_close(pkbuf *" pk );
+.BI "size_t pkbuf_free(pkbuf *" pk ", octet **" p );
+.BI "void pkbuf_snarf(pkbuf *" pk ", const void *" p ", size_t " sz );
+.BI "void pkbuf_want(pkbuf *" pk ", size_t " want );
+.BI "void pkbuf_init(pkbuf *" pk ,
+.BI " void (*" func ")(octet *" b ", size_t " sz ", pkbuf *" pk ,
+.BI " size_t *" keep ", void *" p ),
+.BI " void *" pk );
+.BI "void pkbuf_destroy(pkbuf *" pk );
+.fi
+.SH "DESCRIPTION"
+The declarations in
+.B <mLib/pkbuf.h>
+implement a
+.IR "packet buffer" .
+Given unpredictably-sized chunks of data, the packet buffer extracts
+completed packets of data, with sizes ascertained by a handler
+function.
+.PP
+The state of a packet buffer is stored in an object of type
+.BR pkbuf .
+This is a structure which must be allocated by the caller. The
+structure should normally be considered opaque (see the section on
+.B Disablement
+for an exception to this).
+.SS "Initialization and finalization"
+The function
+.B pkbuf_init
+initializes a packet buffer ready for use. It is given three arguments:
+.TP
+.BI "pkbuf *" pk
+A pointer to the block of memory to use for the packet buffer. The packet
+buffer will allocate memory to store incoming data automatically: this
+structure just contains bookkeeping information.
+.TP
+.nf
+.BI "void (*" func ")(octet *" b ", size_t " sz ", pkbuf *" p ,
+.BI " size_t *" keep ", void *" p )
+.fi
+The
+.I packet-handler
+function to which the packet buffer should pass packets of data when
+they're received.
+.TP
+.BI "void *" p
+A pointer argument to be passed to the function when a packet arrives.
+.PP
+By default, the buffer is
+allocated from the current arena,
+.BR arena_global (3);
+this may be changed by altering the buffer's
+.B a
+member to refer to a different arena at any time when the buffer is
+unallocated.
+.PP
+A packet buffer must be destroyed after use by calling
+.BR pkbuf_destroy ,
+passing it the address of the buffer block.
+.SS "Inserting data into the buffer"
+There are two interfaces for inserting data into the buffer. One's much
+simpler than the other, although it's less expressive.
+.PP
+The simple interface is
+.BR pkbuf_snarf .
+This function is given three arguments: a pointer
+.I pk
+to a packet buffer structure; a pointer
+.I p
+ to a chunk of data to read; and the size
+.I sz
+of the chunk of data. The data is pushed through the packet buffer and
+any complete packets are passed on to the packet handler.
+.PP
+The complex interface is the pair of functions
+.I pkbuf_free
+and
+.IR pkbuf_flush .
+.PP
+The
+.B pkbuf_free
+function returns the address and size of a free portion of the packet
+buffer's memory into which data may be written. The function is passed
+the address
+.I pk
+of the packet buffer. Its result is the size of the free area, and it
+writes the base address of this free space to the location pointed to by
+the argument
+.IR p .
+The caller's data must be written to ascending memory locations starting
+at
+.BI * p
+and no data may be written beyond the end of the free space. However,
+it isn't necessary to completely fill the buffer.
+.PP
+Once the free area has had some data written to it,
+.B pkbuf_flush
+is called to examine the new data and break it into packets. This is
+given three arguments:
+.TP
+.BI "pkbuf *" pk
+The address of the packet buffer.
+.TP
+.BI "octet *" p
+The address at which the new data has been written. This must be the
+base address returned from
+.BR pkbuf_free .
+.TP
+.BI "size_t " len
+The number of bytes which have been written to the buffer.
+.PP
+The
+.B pkbuf_flush
+function breaks the new data into packets as described below, and passes
+each one in turn to the packet-handler function.
+.PP
+The
+.B pkbuf_snarf
+function is trivially implemented in terms of the more complex
+.B pkbuf_free / pkbuf_flush
+interface.
+.SS "Packet breaking and the handler fucntion"
+The function
+.B pkbuf_want
+is used to inform the packet buffer of the expected length of the next
+packet. It is given the pointer
+.I pk
+to the packet buffer and a size
+.I sz
+of the packet.
+.PP
+When enough data has arrived, the packet-handler function is called, and
+passed:
+.TP
+.BI "octet *" b
+A pointer to the packet data in the buffer, or zero to signify
+end-of-file.
+.TP
+.BI "size_t " sz
+The size of the packet, as previously configured via
+.BR pkbuf_want .
+.TP
+.BI "pkbuf *" pk
+A pointer to the packet buffer.
+.TP
+.BI "size_t *" keep
+A location in which to store the number of bytes of the current packet
+to be retained. The bytes kept are from the end of the current packet:
+if you want to keep bytes from the beginning of the packet, you should
+move them into the right place.
+.TP
+.BI "void *" p
+The pointer which was set up in the call to
+.BR pkbuf_init .
+.PP
+.SS "Flushing the remaining data"
+When the client program knows that there's no more data arriving (for
+example, an end-of-file condition exists on its data source) it should
+call the function
+.BR pkbuf_close .
+This will call the handler one final time with a null pointer to inform
+it of the end-of-file.
+.SS "Disablement"
+The packet buffer is intended to be used in higher-level program
+objects, such as the packet selector described in
+.BR selpk (3).
+Unfortunately, a concept from this high level needs to exist at the
+packet buffer level, which complicates the description somewhat. The
+idea is that, when a packet-handler attached to some higher-level object
+decides that it's read enough, it can
+.I disable
+the object so that it doesn't see any more data.
+.PP
+Clearly, since an
+.B pkbuf_flush
+call can emit more than one packet, so it must be aware that the packet
+handler isn't interested in any more packet. However, this fact must
+also be signalled to the higher-level object so that it can detach
+itself from its data source.
+.PP
+Rather than invent some complex interface for this, the packet buffer
+exports one of its structure members,
+.BR flags .
+A higher-level object wishing to disable the packet buffer simply clears
+the bit
+.B PKBUF_ENABLE
+in the flags word.
+.PP
+Disabling a buffer causes an immediate return from
+.BR pkbuf_flush .
+However, it is not permitted for the functions
+.B pkbuf_flush
+or
+.B pkbuf_close
+to be called on a disabled buffer. (This condition isn't checked for;
+it'll just do the wrong thing.) Furthermore, the
+.B pkbuf_snarf
+function does not handle disablement at all, because it would complicate
+the interface so much that it wouldn't have any advantage over the more
+general
+.BR pkbuf_free / pkbuf_flush .
+.SH "SEE ALSO"
+.BR lbuf (3),
+.BR selpk (3),
+.BR mLib (3).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>