]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
Clean up bogus setting of IO_EOF in io_output()
[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 "ioqueue.h"
55 #include "misc.h"
56 #include "queue.h"
57 #include "server.h"
58
59 struct iop {
60     int fd;
61     struct ioqueue *input;
62     struct ioqueue *output;
63     int flags;
64     int bufsize;
65     struct timeval input_timeout;
66 };
67
68 void
69 io_init(void)
70 {
71 }
72
73 struct iop *
74 io_open(int fd, int flags, int bufsize, struct timeval timeout)
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->bufsize = bufsize;
98     iop->input_timeout = timeout;
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)
108 {
109
110     if (iop->input)
111         ioq_destroy(iop->input);
112     if (iop->output)
113         ioq_destroy(iop->output);
114     (void)close(iop->fd);
115     free(iop);
116 }
117
118 /*
119  * Return number of bytes read on success, zero on timeout, early
120  * wakeup or EOF, -1 on error, with errno set appropriately.  In
121  * particular, return -1 with errno set to EAGAIN or EWOULDBLOCK when
122  * no data is available for non-blocking input (WAITFORINPUT false).
123  * Use io_eof() to distinguish timeout and early wakeup from EOF.
124  */
125 int
126 io_input(struct iop *iop, int waitforinput)
127 {
128     char buf[IO_BUFSIZE];
129     int cc;
130     int res;
131
132     /* Not a read IOP */
133     if ((iop->flags & IO_READ) == 0) {
134         errno = EBADF;
135         return -1;
136     }
137     /* IOP is markes as in error. */
138     if (iop->flags & IO_ERROR) {
139         errno = EBADF;
140         return -1;
141     }
142     /* Wait for the file to have input. */
143     if (waitforinput) {
144         res = empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout);
145         if (res < 0) {
146             iop->flags |= IO_ERROR;
147             return -1;
148         } else if (res == 0)
149             return 0;
150     }
151
152     /* Do the actual read. */
153     cc = read(iop->fd, buf, sizeof(buf));
154     if (cc < 0) {
155         if (errno != EAGAIN && errno != EWOULDBLOCK)
156             /* Some form of file error occurred... */
157             iop->flags |= IO_ERROR;
158         return -1;
159     }
160
161     /* We eof'd */
162     if (cc == 0) {
163         iop->flags |= IO_EOF;
164         return 0;
165     }
166
167     /* Append the input to the IOQ. */
168     ioq_append(iop->input, buf, cc);
169     return cc;
170 }
171
172 int
173 io_inputwaiting(struct iop *iop)
174 {
175     return ioq_qsize(iop->input);
176 }
177
178 int
179 io_outputwaiting(struct iop *iop)
180 {
181     return ioq_qsize(iop->output);
182 }
183
184 int
185 io_output(struct iop *iop, int waitforoutput)
186 {
187     struct iovec iov[16];
188     int cc;
189     int n;
190     int remain;
191
192     /* If there is no output waiting. */
193     if (!io_outputwaiting(iop))
194         return 0;
195
196     /* If the iop is not write enabled. */
197     if ((iop->flags & IO_WRITE) == 0)
198         return -1;
199
200     /* If the io is marked as in error... */
201     if (iop->flags & IO_ERROR)
202         return -1;
203
204     /* make the iov point to the data in the queue. */
205     /* I.E., each of the elements in the queue. */
206     /* returns the number of elements in the iov. */
207     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
208
209     if (n <= 0) {
210         return 0;
211     }
212
213     /* wait for the file to be output ready. */
214     if (waitforoutput != IO_NOWAIT) {
215         /* This waits for the file to be ready for writing, */
216         /* and lets other threads run. */
217         empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
218     }
219
220     /* Do the actual write. */
221     cc = writev(iop->fd, iov, n);
222
223     /* if it failed.... */
224     if (cc < 0) {
225         /* Hmm, it would block.  file is opened noblock, soooooo.. */
226         if (errno == EAGAIN || errno == EWOULDBLOCK) {
227             /* If there are remaining bytes, set the IO as remaining.. */
228             remain = ioq_qsize(iop->output);
229             return remain;
230         }
231         iop->flags |= IO_ERROR;
232         return -1;
233     }
234
235     ioq_dequeue(iop->output, cc);
236     return cc;
237 }
238
239 int
240 io_peek(struct iop *iop, char *buf, int nbytes)
241 {
242     if ((iop->flags & IO_READ) == 0)
243         return -1;
244     return ioq_peek(iop->input, buf, nbytes);
245 }
246
247 int
248 io_read(struct iop *iop, char *buf, int nbytes)
249 {
250     int cc;
251
252     if ((iop->flags & IO_READ) == 0)
253         return -1;
254     cc = ioq_peek(iop->input, buf, nbytes);
255     if (cc > 0)
256         ioq_dequeue(iop->input, cc);
257     return cc;
258 }
259
260 int
261 io_write(struct iop *iop, char *buf, int nbytes, int doWait)
262 {
263     int len;
264
265     if ((iop->flags & IO_WRITE) == 0)
266         return -1;
267     ioq_append(iop->output, buf, nbytes);
268     len = ioq_qsize(iop->output);
269     if (len > iop->bufsize) {
270         if (doWait) {
271             io_output_all(iop);
272         } else {
273             /* only try a write every BUFSIZE characters */
274             if (((len - nbytes) % iop->bufsize) < (len % iop->bufsize))
275                 io_output(iop, IO_NOWAIT);
276         }
277     }
278     return nbytes;
279 }
280
281 int
282 io_output_all(struct iop *iop)
283 {
284     int n;
285
286     /*
287      * Mustn't block a player thread while update is pending, or else
288      * a malicous player could delay the update indefinitely
289      */
290     while ((n = io_output(iop, IO_NOWAIT)) > 0 && !play_wrlock_wanted)
291         empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
292
293     return n;
294 }
295
296 int
297 io_gets(struct iop *iop, char *buf, int nbytes)
298 {
299     if ((iop->flags & IO_READ) == 0)
300         return -1;
301     return ioq_gets(iop->input, buf, nbytes);
302 }
303
304 int
305 io_puts(struct iop *iop, char *buf)
306 {
307     if ((iop->flags & IO_WRITE) == 0)
308         return -1;
309     return ioq_puts(iop->output, buf);
310 }
311
312 int
313 io_shutdown(struct iop *iop, int flags)
314 {
315     flags &= (IO_READ | IO_WRITE);
316     if ((iop->flags & flags) != flags)
317         return -1;
318     if (flags & IO_READ) {
319         shutdown(iop->fd, 0);
320         ioq_drain(iop->input);
321     }
322     if (flags & IO_WRITE) {
323         shutdown(iop->fd, 1);
324         ioq_drain(iop->output);
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 int
342 io_fileno(struct iop *iop)
343 {
344     return iop->fd;
345 }