#ifndef TRANSPORT_FD_H
#define TRANSPORT_FD_H
/**
* @file
*
* Support for transport implementations that use POSIX file descriptor streams.
*
* This provides the read/write methods, as well as functions to implement the event-based behaviour.
*/
#include "transport_internal.h"
#include <event2/event.h>
#include <stdbool.h>
// forward-declare
struct transport_fd;
/**
* Our transport_type
*/
extern const struct transport_type transport_fd_type;
/**
* Low-level callback
*/
typedef void (*transport_fd_callback_func) (struct transport_fd *fd, short what, void *arg);
/**
* The fd-based transport implementation
*/
struct transport_fd {
/** Base transport state */
struct transport base;
/** Libevent base to use */
struct event_base *ev_base;
/** OS file descriptor */
evutil_socket_t fd;
/** IO events */
struct event *ev_read, *ev_write;
/** Low-level callback */
transport_fd_callback_func cb_func;
/** Callback context argument */
void *cb_arg;
};
/**
* Get a transport_t pointer from a transport_fd
*/
#define TRANSPORT_FD_BASE(tp_ptr) (&(tp_ptr)->base)
/**
* Invalid OS FD
*/
#define TRANSPORT_FD_INVALID ((evutil_socket_t) -1)
/**
* Implementation of transport_methods::read
*/
err_t transport_fd__read (transport_t *transport, void *buf, size_t *len, error_t *err);
/**
* Implementation of transport_methods::write.
*
* If this gets EAGAIN, it will automatically enable the write event, unless masked out.
*/
err_t transport_fd__write (transport_t *transport, const void *buf, size_t *len, error_t *err);
/**
* Implementation of transport_methods::events.
*
* For TRANSPORT_READ, this will simply apply enable/disable as given.
*
* For TRANSPORT_WRITE, the write event will only be enabled if given in the mask, *and* the ev_write event is currently
* active (via transport_fd_methods_write()); otherwise, the write event will not be enabled.
*/
err_t transport_fd__events (transport_t *transport, short mask, error_t *err);
/**
* Implementation of transport_methods::deinit.
*
* This simply calls transport_fd_deinit().
*/
void transport_fd__deinit (transport_t *transport);
/**
* A transport_fd_callback_func that simply invokes the transport_callback user functions.
*
* Register with a NULL cb_arg.
*/
void transport_fd_callback_user (struct transport_fd *fd, short what, void *arg);
/**
* Initialize the transport_fd to use the given, connected fd, or TRANSPORT_FD_INVALID if we don't yet have an fd.
*
* It is an error to call this if the transport_fd already has an fd set
*
* @param fd the transport_fd state
* @param ev_base the libevent base to use
* @param _fd the OS file descriptor, or TRANSPORT_FD_INVALID
*/
void transport_fd_init (struct transport_fd *fd, struct event_base *ev_base, int _fd);
/**
* Set the fd's nonblocking mode using fcntl.
*/
err_t transport_fd_nonblock (struct transport_fd *fd, bool nonblock);
/**
* Set or replace the fd's event callback. The callback will not be enabled.
*
* The transport must have a valid fd bound to it.
*/
err_t transport_fd_setup (struct transport_fd *fd, transport_fd_callback_func cb_func, void *cb_arg);
/**
* Enable the specified events, any of { TRANSPORT_READ, TRANSPORT_WRITE }.
*/
err_t transport_fd_enable (struct transport_fd *fd, short mask);
/**
* Disable the specified events, any of { TRANSPORT_READ, TRANSPORT_WRITE }.
*/
err_t transport_fd_disable (struct transport_fd *fd, short mask);
/**
* Set the enable/disable state of our events to the given mask.
*/
err_t transport_fd_events (struct transport_fd *fd, short mask);
/**
* Remove any old event callback present, so it will not be called anymore.
*
* It is perfectly safe to call this without any callbacks installed.
*/
void transport_fd_clear (struct transport_fd *fd);
/**
* Setup and enable the default event handlers for transport operation, that is, use transport_fd_callback_user as the
* callback and enable TRANSPORT_READ, unless masked out.
*/
err_t transport_fd_defaults (struct transport_fd *fd);
/**
* Replace the old fd with a new one, maintaining any event callbacks set with transport_fd_callback. If any events were
* enabled before, they are not enabled anymore.
*/
err_t transport_fd_set (struct transport_fd *fd, int _fd);
/**
* Close an opened fd, releasing all resources within our state.
*/
err_t transport_fd_close (struct transport_fd *fd);
/**
* Deinitialize the transport_fd.
*
* This logs a warning if the close() fails.
*
* XXX: this may actually block, I think? SO_LINGER?
*/
void transport_fd_deinit (struct transport_fd *fd);
#endif