]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
0e65c86ed972da2c0d49d72fcbd58bcc54818eb4
[empserver] / src / lib / empthread / io.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  io.c: Arrange for input and output on a file descriptor to be queued.
28  *
29  *  Known contributors to this file:
30  *     Doug Hay, 1998
31  *     Steve McClure, 1998
32  *     Markus Armbruster, 2004-2012
33  *     Ron Koenderink, 2009
34  */
35
36 /*
37  * Arrange for input and output on a file descriptor
38  * to be queued.  Provide main loop -- a mechanism for
39  * blocking across all registered file descriptors, and
40  * reading or writing when appropriate.
41  */
42
43 #include <config.h>
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include <sys/socket.h>
49 #include <sys/types.h>
50 #include <sys/uio.h>
51 #include <unistd.h>
52 #include "empio.h"
53 #include "empthread.h"
54 #include "file.h"
55 #include "ioqueue.h"
56 #include "misc.h"
57 #include "queue.h"
58
59 struct iop {
60     int fd;
61     struct ioqueue *input;
62     struct ioqueue *output;
63     int flags;
64     int bufsize;
65     int last_out;
66     struct timeval input_timeout;
67 };
68
69 void
70 io_init(void)
71 {
72 }
73
74 struct iop *
75 io_open(int fd, int flags, int bufsize, struct timeval timeout)
76 {
77     int fdfl;
78     struct iop *iop;
79
80     flags = flags & (IO_READ | IO_WRITE);
81     if ((flags & (IO_READ | IO_WRITE)) == 0)
82         return NULL;
83
84     fdfl = fcntl(fd, F_GETFL, 0);
85     if (fdfl < 0)
86         return NULL;
87     fdfl |= O_NONBLOCK;
88     if (fcntl(fd, F_SETFL, fdfl) < 0)
89         return NULL;
90
91     iop = malloc(sizeof(struct iop));
92     if (!iop)
93         return NULL;
94     iop->fd = fd;
95     iop->input = NULL;
96     iop->output = NULL;
97     iop->flags = flags;
98     iop->last_out = 0;
99     iop->bufsize = bufsize;
100     iop->input_timeout = timeout;
101     if (flags & IO_READ)
102         iop->input = ioq_create(bufsize);
103     if (flags & IO_WRITE)
104         iop->output = ioq_create(bufsize);
105     return iop;
106 }
107
108 void
109 io_close(struct iop *iop)
110 {
111     char buf[IO_BUFSIZE];
112     int ret;
113
114     while (io_output(iop, 1) > 0) ;
115     shutdown(iop->fd, SHUT_WR);
116     while (empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout) > 0) {
117         ret = read(iop->fd, buf, sizeof(buf));
118         if (ret <= 0)
119             break;
120     }
121     if (iop->input)
122         ioq_destroy(iop->input);
123     if (iop->output)
124         ioq_destroy(iop->output);
125     (void)close(iop->fd);
126     free(iop);
127 }
128
129 /*
130  * Return number of bytes read on success, zero on timeout, early
131  * wakeup or EOF, -1 on error.  In particular, return 0 when no data
132  * is available for non-blocking input (WAITFORINPUT false).
133  * Use io_eof() to distinguish timeout and early wakeup from EOF.
134  */
135 int
136 io_input(struct iop *iop, int waitforinput)
137 {
138     char buf[IO_BUFSIZE];
139     int cc;
140     int res;
141
142     if ((iop->flags & IO_READ) == 0)
143         return -1;
144     if (iop->flags & IO_ERROR)
145         return -1;
146     if (iop->flags & IO_EOF)
147         return 0;
148
149     /* Wait for the file to have input. */
150     if (waitforinput) {
151         res = empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout);
152         if (res < 0) {
153             iop->flags |= IO_ERROR;
154             return -1;
155         } else if (res == 0)
156             return 0;
157     }
158
159     /* Do the actual read. */
160     cc = read(iop->fd, buf, sizeof(buf));
161     if (cc < 0) {
162         if (errno == EAGAIN || errno == EWOULDBLOCK)
163             return 0;
164         iop->flags |= IO_ERROR;
165         return -1;
166     }
167
168     /* We eof'd */
169     if (cc == 0) {
170         iop->flags |= IO_EOF;
171         return 0;
172     }
173
174     /* Append the input to the IOQ. */
175     ioq_append(iop->input, buf, cc);
176     return cc;
177 }
178
179 int
180 io_inputwaiting(struct iop *iop)
181 {
182     return ioq_qsize(iop->input);
183 }
184
185 int
186 io_outputwaiting(struct iop *iop)
187 {
188     return ioq_qsize(iop->output);
189 }
190
191 /*
192  * Write output queued in IOP.
193  * If WAIT, writing may put the thread to sleep.
194  * Return number of bytes written on success, -1 on error.
195  * In particular, return zero when nothing was written because the
196  * queue was empty, or because the write slept and got woken up (only
197  * if WAIT), or because the write refused to sleep (only if !WAIT).
198  */
199 int
200 io_output(struct iop *iop, int wait)
201 {
202     struct iovec iov[16];
203     int n, res, cc;
204
205     if (wait)
206         ef_make_stale();
207
208     if ((iop->flags & IO_WRITE) == 0)
209         return -1;
210
211     if (iop->flags & IO_ERROR)
212         return -1;
213
214     if (!ioq_qsize(iop->output))
215         return 0;
216
217     if (wait) {
218         res = empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
219         if (res == 0)
220             return 0;
221         if (res < 0) {
222             iop->flags |= IO_ERROR;
223             return -1;
224         }
225     }
226
227     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
228     cc = writev(iop->fd, iov, n);
229     if (cc < 0) {
230         if (errno == EAGAIN || errno == EWOULDBLOCK)
231             return 0;
232         iop->flags |= IO_ERROR;
233         return -1;
234     }
235
236     ioq_dequeue(iop->output, cc);
237     iop->last_out = ioq_qsize(iop->output);
238     return cc;
239 }
240
241 /*
242  * Write output queued in IOP if enough have been enqueued.
243  * Write if at least one buffer has been filled since the last write.
244  * If WAIT, writing may put the thread to sleep.
245  * Return number of bytes written on success, -1 on error.
246  * In particular, return zero when nothing was written because the
247  * queue was not long, or the write slept and got woken up (only if
248  * WAIT), or the write refused to sleep (only if !WAIT).
249  */
250 int
251 io_output_if_queue_long(struct iop *iop, int wait)
252 {
253     int len = ioq_qsize(iop->output);
254
255     if (CANT_HAPPEN(iop->last_out > len))
256         iop->last_out = 0;
257     if (len - iop->last_out < iop->bufsize) {
258         if (wait)
259             ef_make_stale();
260         return 0;
261     }
262     return io_output(iop, wait);
263 }
264
265 int
266 io_peek(struct iop *iop, char *buf, int nbytes)
267 {
268     if ((iop->flags & IO_READ) == 0)
269         return -1;
270     return ioq_peek(iop->input, buf, nbytes);
271 }
272
273 int
274 io_read(struct iop *iop, char *buf, int nbytes)
275 {
276     int cc;
277
278     if ((iop->flags & IO_READ) == 0)
279         return -1;
280     cc = ioq_peek(iop->input, buf, nbytes);
281     if (cc > 0)
282         ioq_dequeue(iop->input, cc);
283     return cc;
284 }
285
286 int
287 io_write(struct iop *iop, char *buf, int nbytes)
288 {
289     if ((iop->flags & IO_WRITE) == 0)
290         return -1;
291     ioq_append(iop->output, buf, nbytes);
292     return nbytes;
293 }
294
295 int
296 io_gets(struct iop *iop, char *buf, int nbytes)
297 {
298     if ((iop->flags & IO_READ) == 0)
299         return -1;
300     return ioq_gets(iop->input, buf, nbytes);
301 }
302
303 int
304 io_puts(struct iop *iop, char *buf)
305 {
306     if ((iop->flags & IO_WRITE) == 0)
307         return -1;
308     return ioq_puts(iop->output, buf);
309 }
310
311 int
312 io_shutdown(struct iop *iop, int flags)
313 {
314     flags &= (IO_READ | IO_WRITE);
315     if ((iop->flags & flags) != flags)
316         return -1;
317     if (flags & IO_READ) {
318         shutdown(iop->fd, 0);
319         ioq_drain(iop->input);
320     }
321     if (flags & IO_WRITE) {
322         shutdown(iop->fd, 1);
323         ioq_drain(iop->output);
324         iop->last_out = 0;
325     }
326     return 0;
327 }
328
329 int
330 io_error(struct iop *iop)
331 {
332     return iop->flags & IO_ERROR;
333 }
334
335 int
336 io_eof(struct iop *iop)
337 {
338     return iop->flags & IO_EOF;
339 }
340
341 /*
342  * Discard IOP's buffered input and set its EOF flag.
343  * No more input can be read from IOP.
344  */
345 void
346 io_set_eof(struct iop *iop)
347 {
348     ioq_drain(iop->input);
349     iop->flags |= IO_EOF;
350 }
351
352 int
353 io_fileno(struct iop *iop)
354 {
355     return iop->fd;
356 }