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