#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);
}