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: * (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@176: if ((ERROR_CODE(err) = transport_fd_set(&fifo->base_fd, _fd))) terom@118: return ERROR_CODE(err); terom@118: terom@157: // use default transport event-based behaviour terom@176: if ((ERROR_CODE(err) = transport_fd_defaults(&fifo->base_fd))) terom@157: return ERROR_CODE(err); terom@157: terom@118: // ok terom@118: return SUCCESS; terom@118: } terom@118: terom@118: /** terom@176: * Deinit the fifo, releasing all resources terom@118: */ terom@176: static void fifo_deinit (struct fifo *fifo) terom@118: { terom@176: // deinit base terom@176: transport_fd_deinit(&fifo->base_fd); terom@118: terom@118: // release the path terom@118: free(fifo->path); terom@176: terom@176: fifo->path = NULL; 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@176: if (transport_fd__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@176: static void fifo__deinit (transport_t *transport) terom@118: { terom@157: struct fifo *fifo = transport_check(transport, &fifo_type); terom@118: terom@176: fifo_deinit(fifo); terom@118: } terom@118: terom@118: /* terom@118: * Our sock_stream_type terom@118: */ terom@157: const struct transport_type fifo_type = { terom@176: .base_type = { terom@176: .parent = &transport_fd_type.base_type, terom@176: }, terom@176: .methods = { terom@176: .read = fifo_read, terom@176: .write = NULL, terom@176: .events = transport_fd__events, terom@176: .deinit = fifo__deinit, terom@118: }, terom@118: }; terom@118: terom@176: /** terom@176: * Deinit and free terom@176: */ terom@176: static void fifo_destroy (struct fifo *fifo) terom@176: { terom@176: fifo_deinit(fifo); terom@176: terom@176: free(fifo); terom@176: } terom@176: 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@176: transport_init(&fifo->base_fd.base, &fifo_type, transport_info); terom@176: transport_fd_init(&fifo->base_fd, 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@176: *transport_ptr = &fifo->base_fd.base; 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: }