]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
af6b97dcf6a2a541c7bf99c54f2149ca79784c94
[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 };
67
68 static struct timeval *io_timeout(struct timeval *, time_t);
69
70 void
71 io_init(void)
72 {
73 }
74
75 struct iop *
76 io_open(int fd, int flags, int bufsize)
77 {
78     int fdfl;
79     struct iop *iop;
80
81     flags = flags & (IO_READ | IO_WRITE);
82     if ((flags & (IO_READ | IO_WRITE)) == 0)
83         return NULL;
84
85     fdfl = fcntl(fd, F_GETFL, 0);
86     if (fdfl < 0)
87         return NULL;
88     fdfl |= O_NONBLOCK;
89     if (fcntl(fd, F_SETFL, fdfl) < 0)
90         return NULL;
91
92     iop = malloc(sizeof(struct iop));
93     if (!iop)
94         return NULL;
95     iop->fd = fd;
96     iop->input = NULL;
97     iop->output = NULL;
98     iop->flags = flags;
99     iop->last_out = 0;
100     iop->bufsize = bufsize;
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, time_t deadline)
110 {
111     struct timeval timeout;
112     char buf[IO_BUFSIZE];
113     int ret;
114
115     while (io_output(iop, (time_t)-1) > 0) ;
116     shutdown(iop->fd, SHUT_WR);
117     while (empth_select(iop->fd, EMPTH_FD_READ,
118                         io_timeout(&timeout, deadline)) > 0) {
119         ret = read(iop->fd, buf, sizeof(buf));
120         if (ret <= 0)
121             break;
122     }
123     if (iop->input)
124         ioq_destroy(iop->input);
125     if (iop->output)
126         ioq_destroy(iop->output);
127     (void)close(iop->fd);
128     free(iop);
129 }
130
131 static struct timeval *
132 io_timeout(struct timeval *timeout, time_t deadline)
133 {
134     struct timeval now;
135
136     if (deadline == (time_t)-1)
137         return NULL;            /* no deadline */
138
139     gettimeofday(&now, NULL);
140     if (now.tv_sec >= deadline) {
141         /* deadline reached already */
142         timeout->tv_sec = 0;
143         timeout->tv_usec = 0;
144     } else {
145         /* deadline in future */
146         timeout->tv_sec = deadline - now.tv_sec - 1;
147         timeout->tv_usec = 999999 - now.tv_usec;
148         /* yes, this is 1usec early; sue me */
149     }
150
151     return timeout;
152 }
153
154 /*
155  * Read input from IOP and enqueue it.
156  * Wait at most until DEADLINE for input to arrive.  (time_t)-1 means
157  * wait as long as it takes (no timeout).
158  * Does not yield the processor when DEADLINE is zero.
159  * A wait for input can be cut short by empth_wakeup().
160  * Return number of bytes read on success, -1 on error.
161  * In particular, return zero on timeout, early wakeup or EOF.  Use
162  * io_eof() to distinguish timeout and early wakeup from EOF.
163  */
164 int
165 io_input(struct iop *iop, time_t deadline)
166 {
167     struct timeval timeout;
168     char buf[IO_BUFSIZE];
169     int cc;
170     int res;
171
172     if ((iop->flags & IO_READ) == 0)
173         return -1;
174     if (iop->flags & IO_ERROR)
175         return -1;
176     if (iop->flags & IO_EOF)
177         return 0;
178
179     if (deadline) {
180         res = empth_select(iop->fd, EMPTH_FD_READ,
181                            io_timeout(&timeout, deadline));
182         if (res < 0) {
183             iop->flags |= IO_ERROR;
184             return -1;
185         } else if (res == 0)
186             return 0;
187     }
188
189     cc = read(iop->fd, buf, sizeof(buf));
190     if (cc < 0) {
191         if (errno == EAGAIN || errno == EWOULDBLOCK)
192             return 0;
193         iop->flags |= IO_ERROR;
194         return -1;
195     }
196     if (cc == 0) {
197         iop->flags |= IO_EOF;
198         return 0;
199     }
200
201     ioq_append(iop->input, buf, cc);
202     return cc;
203 }
204
205 int
206 io_inputwaiting(struct iop *iop)
207 {
208     return ioq_qsize(iop->input);
209 }
210
211 int
212 io_outputwaiting(struct iop *iop)
213 {
214     return ioq_qsize(iop->output);
215 }
216
217 /*
218  * Write output queued in IOP.
219  * Wait at most until DEADLINE for input to arrive.  (time_t)-1 means
220  * wait as long as it takes (no timeout).
221  * Does not yield the processor when DEADLINE is zero.
222  * A wait for output can be cut short by empth_wakeup().
223  * Return number of bytes written on success, -1 on error.
224  * In particular, return zero when nothing was written because the
225  * queue is empty, and on timeout or early wakeup.  Use
226  * io_outputwaiting() to distinguish timeout and early wakeup from
227  * empty queue.
228  */
229 int
230 io_output(struct iop *iop, time_t deadline)
231 {
232     struct timeval timeout;
233     struct iovec iov[16];
234     int n, res, cc;
235
236     if (deadline)
237         ef_make_stale();
238
239     if ((iop->flags & IO_WRITE) == 0)
240         return -1;
241
242     if (iop->flags & IO_ERROR)
243         return -1;
244
245     if (!ioq_qsize(iop->output))
246         return 0;
247
248     if (deadline) {
249         res = empth_select(iop->fd, EMPTH_FD_WRITE,
250                            io_timeout(&timeout, deadline));
251         if (res == 0)
252             return 0;
253         if (res < 0) {
254             iop->flags |= IO_ERROR;
255             return -1;
256         }
257     }
258
259     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
260     cc = writev(iop->fd, iov, n);
261     if (cc < 0) {
262         if (errno == EAGAIN || errno == EWOULDBLOCK)
263             return 0;
264         iop->flags |= IO_ERROR;
265         return -1;
266     }
267
268     ioq_dequeue(iop->output, cc);
269     iop->last_out = ioq_qsize(iop->output);
270     return cc;
271 }
272
273 /*
274  * Write output queued in IOP if enough have been enqueued.
275  * Write if at least one buffer has been filled since the last write.
276  * Wait at most until DEADLINE for output to be accepted.  (time_t)-1
277  * means wait as long as it takes (no timeout).
278  * Does not yield the processor when DEADLINE is zero.
279  * A wait for output can be cut short by empth_wakeup().
280  * Return number of bytes written on success, -1 on error.
281  * In particular, return zero when nothing was written because the
282  * queue isn't long, and on timeout or early wakeup.
283  */
284 int
285 io_output_if_queue_long(struct iop *iop, time_t deadline)
286 {
287     int len = ioq_qsize(iop->output);
288
289     if (CANT_HAPPEN(iop->last_out > len))
290         iop->last_out = 0;
291     if (len - iop->last_out < iop->bufsize) {
292         if (deadline)
293             ef_make_stale();
294         return 0;
295     }
296     return io_output(iop, deadline);
297 }
298
299 int
300 io_peek(struct iop *iop, char *buf, int nbytes)
301 {
302     if ((iop->flags & IO_READ) == 0)
303         return -1;
304     return ioq_peek(iop->input, buf, nbytes);
305 }
306
307 int
308 io_read(struct iop *iop, char *buf, int nbytes)
309 {
310     int cc;
311
312     if ((iop->flags & IO_READ) == 0)
313         return -1;
314     cc = ioq_peek(iop->input, buf, nbytes);
315     if (cc > 0)
316         ioq_dequeue(iop->input, cc);
317     return cc;
318 }
319
320 int
321 io_write(struct iop *iop, char *buf, int nbytes)
322 {
323     if ((iop->flags & IO_WRITE) == 0)
324         return -1;
325     ioq_append(iop->output, buf, nbytes);
326     return nbytes;
327 }
328
329 int
330 io_gets(struct iop *iop, char *buf, int nbytes)
331 {
332     if ((iop->flags & IO_READ) == 0)
333         return -1;
334     return ioq_gets(iop->input, buf, nbytes);
335 }
336
337 int
338 io_puts(struct iop *iop, char *buf)
339 {
340     if ((iop->flags & IO_WRITE) == 0)
341         return -1;
342     return ioq_puts(iop->output, buf);
343 }
344
345 int
346 io_shutdown(struct iop *iop, int flags)
347 {
348     flags &= (IO_READ | IO_WRITE);
349     if ((iop->flags & flags) != flags)
350         return -1;
351     if (flags & IO_READ) {
352         shutdown(iop->fd, 0);
353         ioq_drain(iop->input);
354     }
355     if (flags & IO_WRITE) {
356         shutdown(iop->fd, 1);
357         ioq_drain(iop->output);
358         iop->last_out = 0;
359     }
360     return 0;
361 }
362
363 int
364 io_error(struct iop *iop)
365 {
366     return iop->flags & IO_ERROR;
367 }
368
369 int
370 io_eof(struct iop *iop)
371 {
372     return iop->flags & IO_EOF;
373 }
374
375 /*
376  * Discard IOP's buffered input and set its EOF flag.
377  * No more input can be read from IOP.
378  */
379 void
380 io_set_eof(struct iop *iop)
381 {
382     ioq_drain(iop->input);
383     iop->flags |= IO_EOF;
384 }
385
386 int
387 io_fileno(struct iop *iop)
388 {
389     return iop->fd;
390 }