blob: 73229f129e601c29b4b55461d55c2a9fd00ac641 [file] [log] [blame]
/* libnih
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NIH_IO_H
#define NIH_IO_H
#include <sys/types.h>
#include <sys/socket.h>
#include <nih/macros.h>
#include <nih/list.h>
/**
* NihIoType:
*
* Whether an NihIo structure is used for a buffered stream of data, or
* a queue of discreet messages.
**/
typedef enum {
NIH_IO_STREAM,
NIH_IO_MESSAGE
} NihIoType;
/**
* NihIoEvents:
*
* Events that we can watch for, generally used as a bit mask of the events
* that have occurred.
**/
typedef enum {
NIH_IO_NONE = 00,
NIH_IO_READ = 01,
NIH_IO_WRITE = 02,
NIH_IO_EXCEPT = 04,
} NihIoEvents;
/* Predefine the typedefs as we use them in the callbacks */
typedef struct nih_io_watch NihIoWatch;
typedef struct nih_io NihIo;
/**
* NihIoWatcher:
* @data: data pointer given when registered,
* @watch: #NihIoWatch for which an event occurred,
* @events: events that occurred.
*
* An I/O watcher is a function that is called whenever an event occurs
* on a file descriptor or socket being watched. It is safe for the
* watcher to remove the watch during the call.
**/
typedef void (*NihIoWatcher) (void *data, NihIoWatch *watch,
NihIoEvents events);
/**
* NihIoReader:
* @data: data pointer given when registered,
* @io: NihIo with data to be read,
* @buf: buffer data is available in,
* @len: bytes in @buf.
*
* An I/O reader is a function that is called whenever new data or a new
* message has been received on a file descriptor or socket and placed
* into the receive buffer or queue.
*
* In stream mode, @buf and @len will point to the entire receive buffer
* and this function need not clear the buffer, it is entirely permitted
* for the data to be left there. When further data arrives, the buffer
* will be extended and the reader called again.
*
* In message mode, @buf and @len will point to the contents of the oldest
* message in the receive queue. You'll almost certainly want to remove
* this message from the queue, otherwise when a new message arrives, the
* function will still be called with the same oldest message.
*
* It is safe to call nih_io_close() from within the reader function, this
* results in the structure being flagged to be closed when the watcher
* that invokes it has finished. You must not nih_free() @io or cause it
* to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoReader) (void *data, NihIo *io,
const char *buf, size_t len);
/**
* NihIoCloseHandler:
* @data: data pointer given when registered.
* @io: NihIo that closed.
*
* An I/O close handler is a function that is called when the remote end
* of a file descriptor or socket is closed and data can no longer be
* read from it.
*
* It should take appropriate action, which may include closing the
* file descriptor with nih_io_close(). You must not nih_free() @io or
* cause it to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoCloseHandler) (void *data, NihIo *io);
/**
* NihIoErrorHandler:
* @data: data pointer given when registered,
* @io: NihIo that caused the error.
*
* An I/O error handler is a function that is called to handle an error
* raise while reading from the file descriptor or socket. The error
* itself can be obtained using nih_error_get().
*
* It should take appropriate action, which may include closing the
* file descriptor with nih_io_close(). You must not nih_free() @io or
* cause it to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoErrorHandler) (void *data, NihIo *io);
/**
* NihIoWatch:
* @entry: list header,
* @fd: file descriptor,
* @events: events to watch for,
* @watcher: function called when @events occur on @fd,
* @data: pointer passed to @watcher.
*
* This structure represents the most basic kind of I/O handling, a watch
* on a file descriptor or socket that causes a function to be called
* when listed events occur.
*
* The watch can be cancelled by calling nih_list_remove() on the structure
* as they are held in a list internally.
**/
struct nih_io_watch {
NihList entry;
int fd;
NihIoEvents events;
NihIoWatcher watcher;
void *data;
};
/**
* NihIoBuffer:
* @buf: memory allocated for buffer,
* @size: allocated size of @buf,
* @len: number of bytes of @buf used.
*
* This structure is used to represent a buffer holding data that is
* waiting to be sent or processed.
**/
typedef struct nih_io_buffer {
char *buf;
size_t size;
size_t len;
} NihIoBuffer;
/**
* NihIoMessage:
* @entry: list header,
* @addr: address received from or to be sent to,
* @addrlen: length of @addr,
* @data: buffer for message data,
* @control: NULL-terminated array of control messages,
* @int_data: user-supplied integer data,
* @ptr_data: user-supplied pointer data.
*
* This structure is used to represent an individual message waiting in
* a queue to be sent or processed.
*
* When a message is in the queue, it is sometimes useful to be able to
* associate it with the source or destination of the message, for example
* when handling errors. You may use the @int_data or @ptr_member to store
* an integer or pointer value that is useful to you. These are not usually
* initialised.
**/
typedef struct nih_io_message {
NihList entry;
struct sockaddr *addr;
socklen_t addrlen;
NihIoBuffer *data;
struct cmsghdr **control;
union {
int int_data;
void *ptr_data;
};
} NihIoMessage;
/**
* NihIo:
* @type: type of structure,
* @watch: associated file descriptor watch,
* @send_buf: buffer that pools data to be sent (NIH_IO_STREAM),
* @send_q: queue of messages to be sent (NIH_IO_MESSAGE),
* @recv_buf: buffer that pools data received (NIH_IO_STREAM),
* @recv_q: queue of messages received (NIH_IO_MESSAGE),
* @reader: function called when new data in @recv_buf or @recv_q,
* @close_handler: function called when socket closes,
* @error_handler: function called when an error occurs,
* @data: pointer passed to functions,
* @shutdown: TRUE if the structure should be freed once the buffers are empty,
* @free: pointer to variable to set to TRUE if freed during the watcher.
*
* This structure implements more featureful I/O handling than provided by
* an NihIoWatch alone.
*
* When used in the stream mode (@type is NIH_IO_STREAM), it combines an
* NihIoWatch and two NihIoBuffer structures to implement a high-throughput
* alternative to the traditional stdio functions.
*
* Those functions are optimised to reduce the number of read() or write()
* calls made on a file descriptor, and cannot be used to pool large
* amounts of data for processing.
*
* The NihIo functions are instead optimised for being able to queue and
* receive much data as possible, and have the data sent in the background
* or processed at your leisure.
*
* When used in the message mode (@type is NIH_IO_MESSAGE), it combines the
* NihIoWatch with an NihList of NihIoMessage structures to implement
* asynchronous handling of datagram sockets.
**/
struct nih_io {
NihIoType type;
NihIoWatch *watch;
union {
NihIoBuffer *send_buf;
NihList *send_q;
};
union {
NihIoBuffer *recv_buf;
NihList *recv_q;
};
NihIoReader reader;
NihIoCloseHandler close_handler;
NihIoErrorHandler error_handler;
void *data;
int shutdown;
int *free;
};
NIH_BEGIN_EXTERN
extern NihList *nih_io_watches;
void nih_io_init (void);
NihIoWatch * nih_io_add_watch (const void *parent, int fd,
NihIoEvents events,
NihIoWatcher watcher, void *data)
__attribute__ ((warn_unused_result, malloc));
void nih_io_select_fds (int *nfds, fd_set *readfds,
fd_set *writefds, fd_set *exceptfds);
void nih_io_handle_fds (fd_set *readfds, fd_set *writewfds,
fd_set *exceptfds);
NihIoBuffer * nih_io_buffer_new (const void *parent)
__attribute__ ((warn_unused_result, malloc));
int nih_io_buffer_resize (NihIoBuffer *buffer, size_t grow);
char * nih_io_buffer_pop (const void *parent,
NihIoBuffer *buffer, size_t *len)
__attribute__ ((warn_unused_result, malloc));
void nih_io_buffer_shrink (NihIoBuffer *buffer, size_t len);
int nih_io_buffer_push (NihIoBuffer *buffer,
const char *str, size_t len)
__attribute__ ((warn_unused_result));
NihIoMessage *nih_io_message_new (const void *parent)
__attribute__ ((warn_unused_result, malloc));
int nih_io_message_add_control (NihIoMessage *message, int level,
int type, socklen_t len,
const void *data)
__attribute__ ((warn_unused_result));
NihIoMessage *nih_io_message_recv (const void *parent, int fd,
size_t *len)
__attribute__ ((warn_unused_result, malloc));
ssize_t nih_io_message_send (NihIoMessage *message, int fd)
__attribute__ ((warn_unused_result));
NihIo * nih_io_reopen (const void *parent, int fd,
NihIoType type, NihIoReader reader,
NihIoCloseHandler close_handler,
NihIoErrorHandler error_handler,
void *data)
__attribute__ ((warn_unused_result, malloc));
void nih_io_shutdown (NihIo *io);
int nih_io_destroy (NihIo *io);
NihIoMessage *nih_io_read_message (const void *parent, NihIo *io);
void nih_io_send_message (NihIo *io, NihIoMessage *message);
char * nih_io_read (const void *parent, NihIo *io,
size_t *len)
__attribute__ ((warn_unused_result, malloc));
int nih_io_write (NihIo *io, const char *str,
size_t len)
__attribute__ ((warn_unused_result));
char * nih_io_get (const void *parent, NihIo *io,
const char *delim)
__attribute__ ((warn_unused_result, malloc));
int nih_io_printf (NihIo *io, const char *format, ...)
__attribute__ ((warn_unused_result, format (printf, 2, 3)));
int nih_io_set_nonblock (int fd);
int nih_io_set_cloexec (int fd);
ssize_t nih_io_get_family (int fd);
NIH_END_EXTERN
#endif /* NIH_IO_H */