skalibs: the allreadwrite library interface
Keywords: skalibs c unix allreadwrite library libstddjb

libstddjb
libskarnet
skalibs
Software
skarnet.org

# The `allreadwrite` library interface

The following functions are declared in the `skalibs/allreadwrite.h` header, and implemented in the `libskarnet.a` or `libskarnet.so` library.

## General information

`allreadwrite` is a set of IO function helpers. It's the basis for safe reading and writing, either in blocking or in non-blocking mode. The buffer interface relies heavily on `allreadwrite`.

Unless the IO you need is very simple, you generally should not be using the `allreadwrite` functions directly; you should use higher-level APIs such as buffer and bufalloc.

## Function types

`typedef ssize_t io_func (int fd, char *buf, size_t len)`
This is the simplified type of IO functions such as read() and write().

`typedef ssize_t iov_func (int fd, struct iovec const *v, unsigned int vlen)`
This is the simplified type of IO functions such as readv() and writev(), where the content to perform IO on is specified as a scatter/gather array of vlen elements instead of a single string.

`typedef size_t allio_func (int fd, char *buf, size_t len)`
This is the type of an IO operation that expects all of its len bytes to be sent or received, and that will loop around a lower-level IO function until either len bytes have been transmitted or an error has occurred. The return value is the actual number of transmitted bytes; if this value is lesser than len, it means that an error has occurred and `errno` is set.

## Functions

`ssize_t sanitize_read (ssize_t r)`
Reading functions such as `read()` and `fd_read` return a positive number when they succeed, -1 when they fail, and 0 when they read an EOF. No data available on the descriptor when reading in non-blocking mode is treated as a failure: -1 EWOULDBLOCK. But sometimes (namely, in asynchronous IO loops) it's preferrable to handle EOF as an exception condition and EWOULDBLOCK as a normal condition. `sanitize_read()`, when applied to the result of a basic reading function, returns 0 if r is -1 and errno is EWOULDBLOCK (or EAGAIN). If r is zero, it returns -1 EPIPE. Else it returns r.

(No system reading function can ever set errno to EPIPE, and the semantics are appropriate, so EPIPE is a good candidate to signal EOF on reading.)

`ssize_t unsanitize_read (ssize_t r)`
Returns the inverse of `sanitize_read`.

`size_t allreadwrite (io_func *f, int fd, char *s, size_t len)`
*f must be a basic reading or writing function such as `fd_read` or `fd_write`. `allreadwrite()` performs *f on fd, s and len until len bytes have been read or written, or until an error occurs. It returns the total number of handled bytes, and sets errno if this number is not len. `allreadwrite` may block if fd is in blocking mode; if fd is in non-blocking mode, it might set errno to EWOULDBLOCK or EAGAIN.

`size_t allreadwritev (iov_func *f, int fd, struct iovec const *v, unsigned int vlen)`
Like `allreadwrite` but the content to perform IO on is specified as a scatter/gather array of vlen elements instead of a single string.

`ssize_t fd_read (int fd, char *s, size_t len)`
Safe wrapper around the read() function.

`ssize_t fd_write (int fd, char const *s, size_t len)`
Safe wrapper around the write() function.

`ssize_t fd_readv (int fd, struct iovec const *v, unsigned int vlen)`
Safe wrapper around the readv() function.

`ssize_t fd_writev (int fd, struct iovec const *v, unsigned int vlen)`
Safe wrapper around the writev() function.

`ssize_t fd_recv (int fd, char *s, size_t len, unsigned int flags)`
Safe wrapper around the recv() function.

`ssize_t fd_send (int fd, char const *s, size_t len, unsigned int flags)`
Safe wrapper around the send() function.

`size_t allread (int fd, char *s, size_t len)`
Equivalent to `allreadwrite(&fd_read, fd, s, len)` : attempts to read len bytes from fd into s, looping around `fd_read()` if necessary, until either len bytes are read or an error occurs.

`size_t allwrite (int fd, char const *s, size_t len)`
Equivalent to `allreadwrite((io_func *)&fd_write, fd, s, len)` : attempts to write len bytes from s to fd, looping around `fd_write()` if necessary, until either len bytes are written or an error occurs.

`size_t allreadv (int fd, struct iovec *v, unsigned int vlen)`
Like `allread`, but the bytes from fd are read into a scatter/gather array of vlen elements instead of a single string.

`size_t allwritev (int fd, struct iovec const *v, unsigned int vlen)`
Like `allwrite`, but the content to write is taken from a scatter/gather array of vlen elements instead of a single string.