terom@118: /** terom@118: * @file terom@118: * terom@118: * A read-only sock_stream implementation for linux fifo(7). terom@118: */ terom@118: #include "sock_fd.h" terom@118: terom@118: #include terom@118: #include terom@118: #include terom@118: #include terom@118: #include terom@118: terom@118: struct fifo { terom@118: /** The base fd operations */ terom@118: struct sock_fd base_fd; terom@118: terom@118: /** The 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@118: #define FIFO_BASE(sock_ptr) SOCK_FD_BASE(FIFO_FD(sock_ptr)) terom@118: terom@118: /** terom@118: * Get the sock_stream.err pointer from a sock_fifo pointer terom@118: */ terom@118: #define FIFO_ERR(sock_ptr) SOCK_ERR(FIFO_BASE(sock_ptr)) terom@118: 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@118: static err_t fifo_open (struct fifo *fifo, struct error_info *err) terom@118: { terom@118: int fd; terom@118: terom@118: // open(2) the path in non-blocking mode terom@118: // XXX: hardoded read-only terom@118: 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@118: if ((ERROR_CODE(err) = sock_fd_set(FIFO_FD(fifo), fd))) terom@118: return ERROR_CODE(err); terom@118: 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@118: // close if open terom@118: if (FIFO_FD(fifo)->fd >= 0) terom@118: sock_fd_close(FIFO_FD(fifo)); terom@118: terom@118: // release the path terom@118: free(fifo->path); terom@118: free(fifo); 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@118: err_t fifo_read (struct sock_stream *base_sock, void *buf, size_t *len, struct error_info *err) terom@118: { terom@118: struct fifo *fifo = SOCK_FROM_BASE(base_sock, struct fifo); terom@118: terom@118: // passthru ERR_READ_EOF unless it's READ_EOF terom@118: if (sock_fd_read(base_sock, buf, len, err) != ERR_READ_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@118: static void fifo_release (struct sock_stream *base_sock) terom@118: { terom@118: struct fifo *fifo = SOCK_FROM_BASE(base_sock, struct fifo); terom@118: terom@118: fifo_destroy(fifo); terom@118: } terom@118: terom@118: /* terom@118: * Our sock_stream_type terom@118: */ terom@118: static struct sock_stream_type fifo_stream_type = { terom@118: .methods = { terom@118: .read = &fifo_read, terom@118: .write = NULL, terom@118: .event_init = &sock_fd_event_init, terom@118: .event_enable = &sock_fd_event_enable, terom@118: .release = &fifo_release, terom@118: }, terom@118: }; terom@118: terom@118: err_t fifo_open_read (struct sock_stream **stream_ptr, const char *path, struct error_info *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@139: sock_stream_init(FIFO_BASE(fifo), &fifo_stream_type, NULL, NULL); terom@118: sock_fd_init(FIFO_FD(fifo), -1); terom@118: terom@118: // open the fifo terom@118: if (fifo_open(fifo, err)) terom@118: goto error; terom@118: terom@118: // ok terom@118: *stream_ptr = FIFO_BASE(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: }