src/lib/transport_fd.h
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 176 src/transport_fd.h@6750d50ee8cd
permissions -rw-r--r--
some of the lib/transport stuff compiles
#ifndef LIBQMSK_TRANSPORT_FD_H
#define LIBQMSK_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, error_t *err);

/**
 * Close an opened fd, releasing all resources within our state.
 */
err_t transport_fd_close (struct transport_fd *fd, error_t *err);

/**
 * 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