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 } |
|