]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
Generation numbers to catch write back of stale copies
[empserver] / src / lib / empthread / io.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program 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 2 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, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  io.c: Arrange for input and output on a file descriptor to be queued.
29  *
30  *  Known contributors to this file:
31  *      Doug Hay, 1998
32  *      Steve McClure, 1998
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 #include "server.h"
59
60 struct iop {
61     int fd;
62     struct ioqueue *input;
63     struct ioqueue *output;
64     int flags;
65     int bufsize;
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     struct iop *iop;
78
79     flags = flags & (IO_READ | IO_WRITE | IO_NBLOCK | IO_NEWSOCK);
80     if ((flags & (IO_READ | IO_WRITE)) == 0)
81         return NULL;
82     iop = malloc(sizeof(struct iop));
83     if (!iop)
84         return NULL;
85     iop->fd = fd;
86     iop->input = 0;
87     iop->output = 0;
88     iop->flags = 0;
89     iop->input_timeout = timeout;
90     iop->bufsize = bufsize;
91     if ((flags & IO_READ) && (flags & IO_NEWSOCK) == 0)
92         iop->input = ioq_create(bufsize);
93     if ((flags & IO_WRITE) && (flags & IO_NEWSOCK) == 0)
94         iop->output = ioq_create(bufsize);
95     if (flags & IO_NBLOCK)
96         io_noblocking(iop, 1);  /* FIXME check success */
97     iop->flags = flags;
98     return iop;
99 }
100
101 void
102 io_close(struct iop *iop)
103 {
104
105     if (iop->input != 0)
106         ioq_destroy(iop->input);
107     if (iop->output != 0)
108         ioq_destroy(iop->output);
109     (void)close(iop->fd);
110     free(iop);
111 }
112
113 /*
114  * Return number of bytes read on success, zero on timeout, early
115  * wakeup or EOF, -1 on error, with errno set appropriately.  In
116  * particular, return -1 with errno set to EAGAIN or EWOULDBLOCK when
117  * no data is available for non-blocking input (WAITFORINPUT false).
118  * Use io_eof() to distinguish timeout and early wakeup from EOF.
119  */
120 int
121 io_input(struct iop *iop, int waitforinput)
122 {
123     char buf[IO_BUFSIZE];
124     int cc;
125     int res;
126
127     if (waitforinput)
128         ef_make_stale();
129
130     /* Not a read IOP */
131     if ((iop->flags & IO_READ) == 0) {
132         errno = EBADF;
133         return -1;
134     }
135     /* IOP is markes as in error. */
136     if (iop->flags & IO_ERROR) {
137         errno = EBADF;
138         return -1;
139     }
140     /* Wait for the file to have input. */
141     if (waitforinput) {
142         res = empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout);
143         if (res < 0) {
144             iop->flags |= IO_ERROR;
145             return -1;
146         } else if (res == 0)
147             return 0;
148     }
149
150     /* Do the actual read. */
151     cc = read(iop->fd, buf, sizeof(buf));
152     if (cc < 0) {
153         if (errno != EAGAIN && errno != EWOULDBLOCK)
154             /* Some form of file error occurred... */
155             iop->flags |= IO_ERROR;
156         return -1;
157     }
158
159     /* We eof'd */
160     if (cc == 0) {
161         iop->flags |= IO_EOF;
162         return 0;
163     }
164
165     /* Append the input to the IOQ. */
166     ioq_append(iop->input, buf, cc);
167     return cc;
168 }
169
170 int
171 io_inputwaiting(struct iop *iop)
172 {
173     return ioq_qsize(iop->input);
174 }
175
176 int
177 io_outputwaiting(struct iop *iop)
178 {
179     return ioq_qsize(iop->output);
180 }
181
182 int
183 io_output(struct iop *iop, int waitforoutput)
184 {
185     struct iovec iov[16];
186     int cc;
187     int n;
188     int remain;
189
190     if (waitforoutput)
191         ef_make_stale();
192
193     /* If there is no output waiting. */
194     if (!io_outputwaiting(iop))
195         return 0;
196
197     /* If the iop is not write enabled. */
198     if ((iop->flags & IO_WRITE) == 0)
199         return -1;
200
201     /* If the io is marked as in error... */
202     if (iop->flags & IO_ERROR)
203         return -1;
204
205     /* make the iov point to the data in the queue. */
206     /* I.E., each of the elements in the queue. */
207     /* returns the number of elements in the iov. */
208     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
209
210     if (n <= 0) {
211         return 0;
212     }
213
214     /* wait for the file to be output ready. */
215     if (waitforoutput != IO_NOWAIT) {
216         /* This waits for the file to be ready for writing, */
217         /* and lets other threads run. */
218         empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
219     }
220
221     /* Do the actual write. */
222     cc = writev(iop->fd, iov, n);
223
224     /* if it failed.... */
225     if (cc < 0) {
226         /* Hmm, it would block.  file is opened noblock, soooooo.. */
227         if (errno == EAGAIN || errno == EWOULDBLOCK) {
228             /* If there are remaining bytes, set the IO as remaining.. */
229             remain = ioq_qsize(iop->output);
230             return remain;
231         }
232         iop->flags |= IO_ERROR;
233         return -1;
234     }
235
236     /* If no bytes were written, something happened..  Like an EOF. */
237     if (cc == 0) {
238         iop->flags |= IO_EOF;
239         return 0;
240     }
241
242     /* Remove the number of written bytes from the queue. */
243     ioq_dequeue(iop->output, cc);
244
245     return cc;
246 }
247
248 int
249 io_peek(struct iop *iop, char *buf, int nbytes)
250 {
251     if ((iop->flags & IO_READ) == 0)
252         return -1;
253     return ioq_peek(iop->input, buf, nbytes);
254 }
255
256 int
257 io_read(struct iop *iop, char *buf, int nbytes)
258 {
259     int cc;
260
261     if ((iop->flags & IO_READ) == 0)
262         return -1;
263     cc = ioq_peek(iop->input, buf, nbytes);
264     if (cc > 0)
265         ioq_dequeue(iop->input, cc);
266     return cc;
267 }
268
269 int
270 io_write(struct iop *iop, char *buf, int nbytes, int doWait)
271 {
272     int len;
273
274     if (doWait)
275         ef_make_stale();
276
277     if ((iop->flags & IO_WRITE) == 0)
278         return -1;
279     ioq_append(iop->output, buf, nbytes);
280     len = ioq_qsize(iop->output);
281     if (len > iop->bufsize) {
282         if (doWait) {
283             io_output_all(iop);
284         } else {
285             /* only try a write every BUFSIZE characters */
286             if (((len - nbytes) % iop->bufsize) < (len % iop->bufsize))
287                 io_output(iop, IO_NOWAIT);
288         }
289     }
290     return nbytes;
291 }
292
293 int
294 io_output_all(struct iop *iop)
295 {
296     int n;
297
298     ef_make_stale();
299
300     /*
301      * Mustn't block a player thread while update is pending, or else
302      * a malicous player could delay the update indefinitely
303      */
304     while ((n = io_output(iop, IO_NOWAIT)) > 0 && !play_wrlock_wanted)
305         empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
306
307     return n;
308 }
309
310 int
311 io_gets(struct iop *iop, char *buf, int nbytes)
312 {
313     if ((iop->flags & IO_READ) == 0)
314         return -1;
315     return ioq_gets(iop->input, buf, nbytes);
316 }
317
318 int
319 io_puts(struct iop *iop, char *buf)
320 {
321     if ((iop->flags & IO_WRITE) == 0)
322         return -1;
323     return ioq_puts(iop->output, buf);
324 }
325
326 int
327 io_shutdown(struct iop *iop, int flags)
328 {
329     flags &= (IO_READ | IO_WRITE);
330     if ((iop->flags & flags) != flags)
331         return -1;
332     if (flags & IO_READ) {
333         shutdown(iop->fd, 0);
334         ioq_drain(iop->input);
335     }
336     if (flags & IO_WRITE) {
337         shutdown(iop->fd, 1);
338         ioq_drain(iop->output);
339     }
340     return 0;
341 }
342
343 int
344 io_noblocking(struct iop *iop, int value)
345 {
346     int flags;
347
348     flags = fcntl(iop->fd, F_GETFL, 0);
349     if (flags < 0)
350         return -1;
351     if (value == 0)
352         flags &= ~O_NONBLOCK;
353     else
354         flags |= O_NONBLOCK;
355     if (fcntl(iop->fd, F_SETFL, flags) < 0)
356         return -1;
357     if (value == 0)
358         iop->flags &= ~IO_NBLOCK;
359     else
360         iop->flags |= IO_NBLOCK;
361     return 0;
362 }
363
364 int
365 io_error(struct iop *iop)
366 {
367     return iop->flags & IO_ERROR;
368 }
369
370 int
371 io_eof(struct iop *iop)
372 {
373     return iop->flags & IO_EOF;
374 }
375
376 int
377 io_fileno(struct iop *iop)
378 {
379     return iop->fd;
380 }