src/fifo.c
branchnew-transport
changeset 157 1e5674d0eec4
parent 139 55b9dcc2b73a
child 161 d229e4668476
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fifo.c	Tue Apr 28 22:36:36 2009 +0300
@@ -0,0 +1,153 @@
+
+#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;
+};
+
+/**
+ * Get a sock_fd pointer from a sock_fifo pointer
+ */
+#define FIFO_FD(sock_ptr) (&(sock_ptr)->base_fd)
+
+/**
+ * Get a sock_base pointer from a sock_fifo pointer
+ */
+#define FIFO_TRANSPORT(sock_ptr) TRANSPORT_FD_BASE(FIFO_FD(sock_ptr))
+
+
+/**
+ * (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_FD(fifo), _fd)))
+        return ERROR_CODE(err);
+    
+    // use default transport event-based behaviour
+    if ((ERROR_CODE(err) = transport_fd_defaults(FIFO_FD(fifo))))
+        return ERROR_CODE(err);
+
+    // ok
+    return SUCCESS;
+}
+
+/**
+ * Destroy the fifo, releasing all resources
+ */
+static void fifo_destroy (struct fifo *fifo)
+{
+    // destroy base
+    transport_fd_destroy(FIFO_FD(fifo));
+
+    // release the path
+    free(fifo->path);
+}
+
+/**
+ * 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_methods_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_destroy (transport_t *transport)
+{
+    struct fifo *fifo = transport_check(transport, &fifo_type);
+    
+    fifo_destroy(fifo);
+}
+
+/*
+ * Our sock_stream_type
+ */
+const struct transport_type fifo_type = {
+    .methods                = {
+        .read               = fifo_read,
+        .write              = NULL,
+        .events             = transport_fd_methods_events,
+        .destroy            = _fifo_destroy,
+    },
+};
+
+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_TRANSPORT(fifo), &fifo_type, transport_info);
+    transport_fd_init(FIFO_FD(fifo), ev_base, TRANSPORT_FD_INVALID);
+    
+    // open the fifo
+    if (fifo_open(fifo, err))
+        goto error;
+
+    // ok
+    *transport_ptr = FIFO_TRANSPORT(fifo);
+
+    return SUCCESS;
+
+error:
+    // cleanup
+    fifo_destroy(fifo);
+
+    return ERROR_CODE(err);
+}