.TH bytestream 7 .SH NAME bytestream \- length checked input byte stream .SH SYNTAX .B #include .B #include struct bytestream bs; \fBbs_init_iobuf\fP(&bs, buffer_0); // tie bytestream to I/O buffer \fBbs_init_iobuf_size\fP(&bs, buffer_0, 64*1024); unsigned char byte0 = \fBbs_get\fP(&bs); unsigned char byte1 = \fBbs_get\fP(&bs); if (\fBbs_err\fP(&bs)) { // handle error } struct bytestream substream; \fBbs_init_bstream_size\fP(&substream, &bs, byte0*256+byte1); // reading from substream really reads from bs // but does implicit additional range check .SH DESCRIPTION A bytestream is an adapter that can be put in front of a libowfat I/O read buffer, a memory buffer (pointer + size), or another bytestream. The bytestream API will do two things for you: Implicit range checks and well defined error behavior. If a range check fails, the bytestream is set to the error state, and stays in the error state. Reading from a bytestream in the error state yields 0 bytes, while the stream stays in the error state. The goal of this API design was to end up with parsing code that is obviously correct. The risk of forgetting a range check or of having an integer overflow in one is delegated to the bytestream API. The parsing code can in most cases simply read data without checking for errors, and only in the end there is a single check that the bytestream is not in the error state. Bytestreams can also be nested. Creating a nested bytestream with a size limit that exceeds the available space in the parent stream will set it to the error state right from the start. .SH EXAMPLE char inbuf[8192]; struct sockaddr_in sa; struct sockaddr_len salen = sizeof sa; ssize_t msgsize = recvfrom(input_socket, inbuf, sizeof(inbuf), 0, &sa, &salen); assert(msgsize > 0); struct bytestream bs; init_bs_membuf(&bs, inbuf, msgsize); // implicit range check that there is 2 bytes left uint16_t version = prs_u16(&bs); // little endian 16 bit // implicit range check that there is 4 bytes left uint32_t hdrlen = prs_u32_big(&bs); // big endian 32 bit struct bytestream pktbs; // implicit range check that hdrlen fits in the packet bs_init_bstream_size(&pktbs, &bs, hdrlen); // implicit range check that hdrlen fits in the packet uint32_t strlen = prs_u32_big(&pktbs); // big endian 32 bit // not technically needed but helpful on mmu-less systems if (len_b32 > sizeof(inbuf)) abort(); char* str = malloc(len_b32); assert(str); // implicit range check that whole string fits in header prs_readblob(&pktbs, str, len_be32); // only have to check for error once at the end if (bs_err(&bs)) { free(str); // ... handle errors ... } .SH "SEE ALSO" buffer_flush(3)