--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/fifo.c Thu May 28 01:17:36 2009 +0300
@@ -0,0 +1,157 @@
+
+#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);
+}