1 #define _POSIX_C_SOURCE 200809L
2 
3 #include "pipe.h"
4 
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <limits.h>
8 #include <poll.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 
12 #include "error.h"
13 #include "handle.h"
14 
15 const int PIPE_INVALID = -1;
16 
17 const short PIPE_EVENT_IN = POLLIN;
18 const short PIPE_EVENT_OUT = POLLOUT;
19 
pipe_init(int * read,int * write)20 int pipe_init(int *read, int *write)
21 {
22   ASSERT(read);
23   ASSERT(write);
24 
25   int pair[] = { PIPE_INVALID, PIPE_INVALID };
26   int r = -1;
27 
28   r = pipe(pair);
29   if (r < 0) {
30     r = -errno;
31     goto finish;
32   }
33 
34   r = handle_cloexec(pair[0], true);
35   if (r < 0) {
36     goto finish;
37   }
38 
39   r = handle_cloexec(pair[1], true);
40   if (r < 0) {
41     goto finish;
42   }
43 
44   *read = pair[0];
45   *write = pair[1];
46 
47   pair[0] = PIPE_INVALID;
48   pair[1] = PIPE_INVALID;
49 
50 finish:
51   pipe_destroy(pair[0]);
52   pipe_destroy(pair[1]);
53 
54   return r;
55 }
56 
pipe_nonblocking(int pipe,bool enable)57 int pipe_nonblocking(int pipe, bool enable)
58 {
59   int r = -1;
60 
61   r = fcntl(pipe, F_GETFL, 0);
62   if (r < 0) {
63     return -errno;
64   }
65 
66   r = enable ? r | O_NONBLOCK : r & ~O_NONBLOCK;
67 
68   r = fcntl(pipe, F_SETFL, r);
69 
70   return r < 0 ? -errno : 0;
71 }
72 
pipe_read(int pipe,uint8_t * buffer,size_t size)73 int pipe_read(int pipe, uint8_t *buffer, size_t size)
74 {
75   ASSERT(pipe != PIPE_INVALID);
76   ASSERT(buffer);
77 
78   int r = (int) read(pipe, buffer, size);
79 
80   if (r == 0) {
81     // `read` returns 0 to indicate the other end of the pipe was closed.
82     return -EPIPE;
83   }
84 
85   return r < 0 ? -errno : r;
86 }
87 
pipe_write(int pipe,const uint8_t * buffer,size_t size)88 int pipe_write(int pipe, const uint8_t *buffer, size_t size)
89 {
90   ASSERT(pipe != PIPE_INVALID);
91   ASSERT(buffer);
92 
93   int r = (int) write(pipe, buffer, size);
94 
95   return r < 0 ? -errno : r;
96 }
97 
pipe_poll(pipe_event_source * sources,size_t num_sources,int timeout)98 int pipe_poll(pipe_event_source *sources, size_t num_sources, int timeout)
99 {
100   ASSERT(num_sources <= INT_MAX);
101 
102   struct pollfd *pollfds = NULL;
103   int r = -1;
104 
105   pollfds = calloc(num_sources, sizeof(struct pollfd));
106   if (pollfds == NULL) {
107     r = -errno;
108     goto finish;
109   }
110 
111   for (size_t i = 0; i < num_sources; i++) {
112     pollfds[i].fd = sources[i].pipe;
113     pollfds[i].events = sources[i].interests;
114   }
115 
116   r = poll(pollfds, (nfds_t) num_sources, timeout);
117   if (r < 0) {
118     r = -errno;
119     goto finish;
120   }
121 
122   for (size_t i = 0; i < num_sources; i++) {
123     sources[i].events = pollfds[i].revents;
124   }
125 
126 finish:
127   free(pollfds);
128 
129   return r;
130 }
131 
pipe_shutdown(int pipe)132 int pipe_shutdown(int pipe)
133 {
134   (void) pipe;
135   return 0;
136 }
137 
pipe_destroy(int pipe)138 int pipe_destroy(int pipe)
139 {
140   return handle_destroy(pipe);
141 }
142