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