src/lib/fifo.c
branchnew-lib-errors
changeset 219 cefec18b8268
parent 176 6750d50ee8cd
equal deleted inserted replaced
218:5229a5d098b2 219:cefec18b8268
       
     1 
       
     2 #include "fifo.h"
       
     3 #include "transport_fd.h"
       
     4 
       
     5 #include <stdlib.h>
       
     6 #include <sys/types.h>
       
     7 #include <sys/stat.h>
       
     8 #include <fcntl.h>
       
     9 #include <string.h>
       
    10 
       
    11 /**
       
    12  * Our transport_type
       
    13  */
       
    14 extern const struct transport_type fifo_type;
       
    15 
       
    16 /**
       
    17  * The fifo state
       
    18  */
       
    19 struct fifo {
       
    20     /** The FD-based state */
       
    21     struct transport_fd base_fd;
       
    22     
       
    23     /** Path to the fifo */
       
    24     char *path;
       
    25 };
       
    26 
       
    27 /**
       
    28  * (re)open the fifo, closing it if already open, and keeping any event callbacks registered.
       
    29  */
       
    30 static err_t fifo_open (struct fifo *fifo, error_t *err)
       
    31 {
       
    32     int _fd;
       
    33 
       
    34     // open(2) the path in non-blocking read-only mode
       
    35     if ((_fd = open(fifo->path, O_RDONLY | O_NONBLOCK)) < 0)
       
    36         RETURN_SET_ERROR_ERRNO(err, ERR_OPEN);
       
    37 
       
    38     // set the new fd
       
    39     if ((ERROR_CODE(err) = transport_fd_set(&fifo->base_fd, _fd)))
       
    40         return ERROR_CODE(err);
       
    41     
       
    42     // use default transport event-based behaviour
       
    43     if ((ERROR_CODE(err) = transport_fd_defaults(&fifo->base_fd)))
       
    44         return ERROR_CODE(err);
       
    45 
       
    46     // ok
       
    47     return SUCCESS;
       
    48 }
       
    49 
       
    50 /**
       
    51  * Deinit the fifo, releasing all resources
       
    52  */
       
    53 static void fifo_deinit (struct fifo *fifo)
       
    54 {
       
    55     // deinit base
       
    56     transport_fd_deinit(&fifo->base_fd);
       
    57 
       
    58     // release the path
       
    59     free(fifo->path);
       
    60 
       
    61     fifo->path = NULL;
       
    62 }
       
    63 
       
    64 /**
       
    65  * sock_stream_methods::read implementation.
       
    66  *
       
    67  * Try and do a normal sock_fd_read call, but re-open with EAGAIN on EOF
       
    68  */
       
    69 err_t fifo_read (transport_t *transport, void *buf, size_t *len, struct error_info *err)
       
    70 {
       
    71     struct fifo *fifo = transport_check(transport, &fifo_type);
       
    72 
       
    73     // trap READ_EOF
       
    74     if (transport_fd__read(transport, buf, len, err) != ERR_EOF)
       
    75         return ERROR_CODE(err);
       
    76     
       
    77     // re-open it
       
    78     // XXX: re-add events?
       
    79     if (fifo_open(fifo, err))
       
    80         goto error;
       
    81 
       
    82     // ok, act as if it was EAGAIN
       
    83     *len = 0;
       
    84 
       
    85     return SUCCESS;
       
    86 
       
    87 error:
       
    88     return ERROR_CODE(err);
       
    89 }
       
    90 
       
    91 /**
       
    92  * sock_stream_methods::release implementation
       
    93  */
       
    94 static void fifo__deinit (transport_t *transport)
       
    95 {
       
    96     struct fifo *fifo = transport_check(transport, &fifo_type);
       
    97     
       
    98     fifo_deinit(fifo);
       
    99 }
       
   100 
       
   101 /*
       
   102  * Our sock_stream_type
       
   103  */
       
   104 const struct transport_type fifo_type = {
       
   105     .base_type = {
       
   106         .parent     = &transport_fd_type.base_type,
       
   107     },
       
   108     .methods = {
       
   109         .read       = fifo_read,
       
   110         .write      = NULL,
       
   111         .events     = transport_fd__events,
       
   112         .deinit     = fifo__deinit,
       
   113     },
       
   114 };
       
   115 
       
   116 /**
       
   117  * Deinit and free
       
   118  */
       
   119 static void fifo_destroy (struct fifo *fifo)
       
   120 {
       
   121     fifo_deinit(fifo);
       
   122 
       
   123     free(fifo);
       
   124 }
       
   125 
       
   126 err_t fifo_open_read (struct transport_info *transport_info, transport_t **transport_ptr, struct event_base *ev_base,
       
   127         const char *path, error_t *err)
       
   128 {
       
   129     struct fifo *fifo;
       
   130 
       
   131     // alloc
       
   132     if ((fifo = calloc(1, sizeof(*fifo))) == NULL)
       
   133         return SET_ERROR(err, ERR_CALLOC);
       
   134 
       
   135     // copy the path
       
   136     if ((fifo->path = strdup(path)) == NULL)
       
   137         return SET_ERROR(err, ERR_STRDUP);
       
   138 
       
   139     // init
       
   140     transport_init(&fifo->base_fd.base, &fifo_type, transport_info);
       
   141     transport_fd_init(&fifo->base_fd, ev_base, TRANSPORT_FD_INVALID);
       
   142     
       
   143     // open the fifo
       
   144     if (fifo_open(fifo, err))
       
   145         goto error;
       
   146 
       
   147     // ok
       
   148     *transport_ptr = &fifo->base_fd.base;
       
   149 
       
   150     return SUCCESS;
       
   151 
       
   152 error:
       
   153     // cleanup
       
   154     fifo_destroy(fifo);
       
   155 
       
   156     return ERROR_CODE(err);
       
   157 }