src/lib/fifo.c
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 176 src/fifo.c@6750d50ee8cd
permissions -rw-r--r--
some of the lib/transport stuff compiles

#include "fifo.h"
#include "transport_fd.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

/**
 * Our transport_type
 */
extern const struct transport_type fifo_type;

/**
 * The fifo state
 */
struct fifo {
    /** The FD-based state */
    struct transport_fd base_fd;
    
    /** Path to the fifo */
    char *path;
};

/**
 * (re)open the fifo, closing it if already open, and keeping any event callbacks registered.
 */
static err_t fifo_open (struct fifo *fifo, error_t *err)
{
    int _fd;

    // open(2) the path in non-blocking read-only mode
    if ((_fd = open(fifo->path, O_RDONLY | O_NONBLOCK)) < 0)
        RETURN_SET_ERROR_ERRNO(err, ERR_OPEN);

    // set the new fd
    if ((ERROR_CODE(err) = transport_fd_set(&fifo->base_fd, _fd)))
        return ERROR_CODE(err);
    
    // use default transport event-based behaviour
    if ((ERROR_CODE(err) = transport_fd_defaults(&fifo->base_fd)))
        return ERROR_CODE(err);

    // ok
    return SUCCESS;
}

/**
 * Deinit the fifo, releasing all resources
 */
static void fifo_deinit (struct fifo *fifo)
{
    // deinit base
    transport_fd_deinit(&fifo->base_fd);

    // release the path
    free(fifo->path);

    fifo->path = NULL;
}

/**
 * sock_stream_methods::read implementation.
 *
 * Try and do a normal sock_fd_read call, but re-open with EAGAIN on EOF
 */
err_t fifo_read (transport_t *transport, void *buf, size_t *len, struct error_info *err)
{
    struct fifo *fifo = transport_check(transport, &fifo_type);

    // trap READ_EOF
    if (transport_fd__read(transport, buf, len, err) != ERR_EOF)
        return ERROR_CODE(err);
    
    // re-open it
    // XXX: re-add events?
    if (fifo_open(fifo, err))
        goto error;

    // ok, act as if it was EAGAIN
    *len = 0;

    return SUCCESS;

error:
    return ERROR_CODE(err);
}

/**
 * sock_stream_methods::release implementation
 */
static void fifo__deinit (transport_t *transport)
{
    struct fifo *fifo = transport_check(transport, &fifo_type);
    
    fifo_deinit(fifo);
}

/*
 * Our sock_stream_type
 */
const struct transport_type fifo_type = {
    .base_type = {
        .parent     = &transport_fd_type.base_type,
    },
    .methods = {
        .read       = fifo_read,
        .write      = NULL,
        .events     = transport_fd__events,
        .deinit     = fifo__deinit,
    },
};

/**
 * Deinit and free
 */
static void fifo_destroy (struct fifo *fifo)
{
    fifo_deinit(fifo);

    free(fifo);
}

err_t fifo_open_read (struct transport_info *transport_info, transport_t **transport_ptr, struct event_base *ev_base,
        const char *path, error_t *err)
{
    struct fifo *fifo;

    // alloc
    if ((fifo = calloc(1, sizeof(*fifo))) == NULL)
        return SET_ERROR(err, ERR_CALLOC);

    // copy the path
    if ((fifo->path = strdup(path)) == NULL)
        return SET_ERROR(err, ERR_STRDUP);

    // init
    transport_init(&fifo->base_fd.base, &fifo_type, transport_info);
    transport_fd_init(&fifo->base_fd, ev_base, TRANSPORT_FD_INVALID);
    
    // open the fifo
    if (fifo_open(fifo, err))
        goto error;

    // ok
    *transport_ptr = &fifo->base_fd.base;

    return SUCCESS;

error:
    // cleanup
    fifo_destroy(fifo);

    return ERROR_CODE(err);
}