terom@157: terom@157: #include "fifo.h" terom@157: #include "transport_fd.h" terom@118: terom@118: #include terom@118: #include terom@118: #include terom@118: #include terom@118: #include terom@118: terom@157: /** terom@157: * Our transport_type terom@157: */ terom@157: extern const struct transport_type fifo_type; terom@157: terom@157: /** terom@157: * The fifo state terom@157: */ terom@118: struct fifo { terom@157: /** The FD-based state */ terom@157: struct transport_fd base_fd; terom@118: terom@157: /** Path to the fifo */ terom@118: char *path; terom@118: }; terom@118: terom@118: /** terom@118: * Get a sock_fd pointer from a sock_fifo pointer terom@118: */ terom@118: #define FIFO_FD(sock_ptr) (&(sock_ptr)->base_fd) terom@118: terom@118: /** terom@118: * Get a sock_base pointer from a sock_fifo pointer terom@118: */ terom@157: #define FIFO_TRANSPORT(sock_ptr) TRANSPORT_FD_BASE(FIFO_FD(sock_ptr)) terom@118: terom@118: terom@118: /** terom@118: * (re)open the fifo, closing it if already open, and keeping any event callbacks registered. terom@118: */ terom@157: static err_t fifo_open (struct fifo *fifo, error_t *err) terom@118: { terom@157: int _fd; terom@118: terom@157: // open(2) the path in non-blocking read-only mode terom@157: if ((_fd = open(fifo->path, O_RDONLY | O_NONBLOCK)) < 0) terom@118: RETURN_SET_ERROR_ERRNO(err, ERR_OPEN); terom@118: terom@118: // set the new fd terom@157: if ((ERROR_CODE(err) = transport_fd_set(FIFO_FD(fifo), _fd))) terom@118: return ERROR_CODE(err); terom@118: terom@157: // use default transport event-based behaviour terom@157: if ((ERROR_CODE(err) = transport_fd_defaults(FIFO_FD(fifo)))) terom@157: return ERROR_CODE(err); terom@157: terom@118: // ok terom@118: return SUCCESS; terom@118: } terom@118: terom@118: /** terom@118: * Destroy the fifo, releasing all resources terom@118: */ terom@118: static void fifo_destroy (struct fifo *fifo) terom@118: { terom@157: // destroy base terom@157: transport_fd_destroy(FIFO_FD(fifo)); terom@118: terom@118: // release the path terom@118: free(fifo->path); terom@118: } terom@118: terom@118: /** terom@118: * sock_stream_methods::read implementation. terom@118: * terom@118: * Try and do a normal sock_fd_read call, but re-open with EAGAIN on EOF terom@118: */ terom@157: err_t fifo_read (transport_t *transport, void *buf, size_t *len, struct error_info *err) terom@118: { terom@157: struct fifo *fifo = transport_check(transport, &fifo_type); terom@118: terom@157: // trap READ_EOF terom@157: if (transport_fd_methods_read(transport, buf, len, err) != ERR_EOF) terom@118: return ERROR_CODE(err); terom@118: terom@118: // re-open it terom@118: // XXX: re-add events? terom@118: if (fifo_open(fifo, err)) terom@118: goto error; terom@118: terom@118: // ok, act as if it was EAGAIN terom@118: *len = 0; terom@118: terom@118: return SUCCESS; terom@118: terom@118: error: terom@118: return ERROR_CODE(err); terom@118: } terom@118: terom@118: /** terom@118: * sock_stream_methods::release implementation terom@118: */ terom@157: static void _fifo_destroy (transport_t *transport) terom@118: { terom@157: struct fifo *fifo = transport_check(transport, &fifo_type); terom@118: terom@118: fifo_destroy(fifo); terom@118: } terom@118: terom@118: /* terom@118: * Our sock_stream_type terom@118: */ terom@157: const struct transport_type fifo_type = { terom@161: .parent = &transport_fd_type, terom@118: .methods = { terom@157: .read = fifo_read, terom@118: .write = NULL, terom@157: .events = transport_fd_methods_events, terom@157: .destroy = _fifo_destroy, terom@118: }, terom@118: }; terom@118: terom@157: err_t fifo_open_read (struct transport_info *transport_info, transport_t **transport_ptr, struct event_base *ev_base, terom@157: const char *path, error_t *err) terom@118: { terom@118: struct fifo *fifo; terom@118: terom@118: // alloc terom@118: if ((fifo = calloc(1, sizeof(*fifo))) == NULL) terom@118: return SET_ERROR(err, ERR_CALLOC); terom@118: terom@118: // copy the path terom@118: if ((fifo->path = strdup(path)) == NULL) terom@118: return SET_ERROR(err, ERR_STRDUP); terom@118: terom@118: // init terom@157: transport_init(FIFO_TRANSPORT(fifo), &fifo_type, transport_info); terom@157: transport_fd_init(FIFO_FD(fifo), ev_base, TRANSPORT_FD_INVALID); terom@157: terom@118: // open the fifo terom@118: if (fifo_open(fifo, err)) terom@118: goto error; terom@118: terom@118: // ok terom@157: *transport_ptr = FIFO_TRANSPORT(fifo); terom@118: terom@118: return SUCCESS; terom@118: terom@118: error: terom@118: // cleanup terom@118: fifo_destroy(fifo); terom@118: terom@118: return ERROR_CODE(err); terom@118: }