]> git.pond.sub.org Git - empserver/blob - src/lib/gen/io.c
ab2bebda4b8b9a62e526ca79c7ad2c78c858d805
[empserver] / src / lib / gen / io.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2007, 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  */
34
35 /*
36  * Arrange for input and output on a file descriptor
37  * to be queued.  Provide main loop -- a mechanism for
38  * blocking across all registered file descriptors, and
39  * reading or writing when appropriate.
40  */
41
42 #include <config.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/uio.h>
49 #if !defined(_WIN32)
50 #include <sys/file.h>
51 #endif
52 #include <sys/socket.h>
53 #include <unistd.h>
54 #include <time.h>
55
56 #include "empio.h"
57 #include "ioqueue.h"
58 #include "misc.h"
59 #include "queue.h"
60 #include "server.h"
61
62 #include "empthread.h"
63
64 struct iop {
65     int fd;
66     struct ioqueue *input;
67     struct ioqueue *output;
68     int flags;
69     int bufsize;
70 };
71
72 void
73 io_init(void)
74 {
75 }
76
77 struct iop *
78 io_open(int fd, int flags, int bufsize)
79 {
80     struct iop *iop;
81
82     flags = flags & (IO_READ | IO_WRITE | IO_NBLOCK | IO_NEWSOCK);
83     if ((flags & (IO_READ | IO_WRITE)) == 0)
84         return NULL;
85     iop = malloc(sizeof(struct iop));
86     if (!iop)
87         return NULL;
88     iop->fd = fd;
89     iop->input = 0;
90     iop->output = 0;
91     iop->flags = 0;
92     iop->bufsize = bufsize;
93     if ((flags & IO_READ) && (flags & IO_NEWSOCK) == 0)
94         iop->input = ioq_create(bufsize);
95     if ((flags & IO_WRITE) && (flags & IO_NEWSOCK) == 0)
96         iop->output = ioq_create(bufsize);
97     if (flags & IO_NBLOCK)
98         io_noblocking(iop, 1);  /* FIXME check success */
99     iop->flags = flags;
100     return iop;
101 }
102
103 void
104 io_close(struct iop *iop)
105 {
106
107     if (iop->input != 0)
108         ioq_destroy(iop->input);
109     if (iop->output != 0)
110         ioq_destroy(iop->output);
111     (void)close(iop->fd);
112     free(iop);
113 }
114
115 int
116 io_input(struct iop *iop, int waitforinput)
117 {
118     char buf[IO_BUFSIZE];
119     int cc;
120
121     /* Not a read IOP */
122     if ((iop->flags & IO_READ) == 0)
123         return -1;
124     /* IOP is markes as in error. */
125     if (iop->flags & IO_ERROR)
126         return -1;
127     /* Wait for the file to have input. */
128     if (waitforinput) {
129         empth_select(iop->fd, EMPTH_FD_READ);
130     }
131     /* Do the actual read. */
132     cc = read(iop->fd, buf, sizeof(buf));
133     if (cc < 0) {
134         /* would block, so nothing to read. */
135         if (errno == EAGAIN || errno == EWOULDBLOCK)
136             return 0;
137
138         /* Some form of file error occurred... */
139         iop->flags |= IO_ERROR;
140         return -1;
141     }
142
143     /* We eof'd */
144     if (cc == 0) {
145         iop->flags |= IO_EOF;
146         return 0;
147     }
148
149     /* Append the input to the IOQ. */
150     ioq_append(iop->input, buf, cc);
151     return cc;
152 }
153
154 int
155 io_inputwaiting(struct iop *iop)
156 {
157     return ioq_qsize(iop->input);
158 }
159
160 int
161 io_outputwaiting(struct iop *iop)
162 {
163     return ioq_qsize(iop->output);
164 }
165
166 int
167 io_output(struct iop *iop, int waitforoutput)
168 {
169     struct iovec iov[16];
170     int cc;
171     int n;
172     int remain;
173
174     /* If there is no output waiting. */
175     if (!io_outputwaiting(iop))
176         return 0;
177
178     /* If the iop is not write enabled. */
179     if ((iop->flags & IO_WRITE) == 0)
180         return -1;
181
182     /* If the io is marked as in error... */
183     if (iop->flags & IO_ERROR)
184         return -1;
185
186     /* make the iov point to the data in the queue. */
187     /* I.E., each of the elements in the queue. */
188     /* returns the number of elements in the iov. */
189     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
190
191     if (n <= 0) {
192         return 0;
193     }
194
195     /* wait for the file to be output ready. */
196     if (waitforoutput != IO_NOWAIT) {
197         /* This waits for the file to be ready for writing, */
198         /* and lets other threads run. */
199         empth_select(iop->fd, EMPTH_FD_WRITE);
200     }
201
202     /* Do the actual write. */
203     cc = writev(iop->fd, iov, n);
204
205     /* if it failed.... */
206     if (cc < 0) {
207         /* Hmm, it would block.  file is opened noblock, soooooo.. */
208         if (errno == EAGAIN || errno == EWOULDBLOCK) {
209             /* If there are remaining bytes, set the IO as remaining.. */
210             remain = ioq_qsize(iop->output);
211             return remain;
212         }
213         iop->flags |= IO_ERROR;
214         return -1;
215     }
216
217     /* If no bytes were written, something happened..  Like an EOF. */
218     if (cc == 0) {
219         iop->flags |= IO_EOF;
220         return 0;
221     }
222
223     /* Remove the number of written bytes from the queue. */
224     ioq_dequeue(iop->output, cc);
225
226     return cc;
227 }
228
229 int
230 io_peek(struct iop *iop, char *buf, int nbytes)
231 {
232     if ((iop->flags & IO_READ) == 0)
233         return -1;
234     return ioq_peek(iop->input, buf, nbytes);
235 }
236
237 int
238 io_read(struct iop *iop, char *buf, int nbytes)
239 {
240     int cc;
241
242     if ((iop->flags & IO_READ) == 0)
243         return -1;
244     cc = ioq_peek(iop->input, buf, nbytes);
245     if (cc > 0)
246         ioq_dequeue(iop->input, cc);
247     return cc;
248 }
249
250 int
251 io_write(struct iop *iop, char *buf, int nbytes, int doWait)
252 {
253     int len;
254
255     if ((iop->flags & IO_WRITE) == 0)
256         return -1;
257     ioq_append(iop->output, buf, nbytes);
258     len = ioq_qsize(iop->output);
259     if (len > iop->bufsize) {
260         if (doWait) {
261             io_output_all(iop);
262         } else {
263             /* only try a write every BUFSIZE characters */
264             if (((len - nbytes) % iop->bufsize) < (len % iop->bufsize))
265                 io_output(iop, IO_NOWAIT);
266         }
267     }
268     return nbytes;
269 }
270
271 int
272 io_output_all(struct iop *iop)
273 {
274     int n;
275
276     /*
277      * Mustn't block a player thread while update is pending, or else
278      * a malicous player could delay the update indefinitely
279      */
280     while ((n = io_output(iop, IO_NOWAIT)) > 0 && !play_wrlock_wanted)
281         empth_select(iop->fd, EMPTH_FD_WRITE);
282
283     return n;
284 }
285
286 int
287 io_gets(struct iop *iop, char *buf, int nbytes)
288 {
289     if ((iop->flags & IO_READ) == 0)
290         return -1;
291     return ioq_gets(iop->input, buf, nbytes);
292 }
293
294 int
295 io_puts(struct iop *iop, char *buf)
296 {
297     if ((iop->flags & IO_WRITE) == 0)
298         return -1;
299     return ioq_puts(iop->output, buf);
300 }
301
302 int
303 io_shutdown(struct iop *iop, int flags)
304 {
305     flags &= (IO_READ | IO_WRITE);
306     if ((iop->flags & flags) != flags)
307         return -1;
308     if (flags & IO_READ) {
309         shutdown(iop->fd, 0);
310         ioq_drain(iop->input);
311     }
312     if (flags & IO_WRITE) {
313         shutdown(iop->fd, 1);
314         ioq_drain(iop->output);
315     }
316     return 0;
317 }
318
319 int
320 io_noblocking(struct iop *iop, int value)
321 {
322     int flags;
323
324     flags = fcntl(iop->fd, F_GETFL, 0);
325     if (flags < 0)
326         return -1;
327     if (value == 0)
328         flags &= ~O_NONBLOCK;
329     else
330         flags |= O_NONBLOCK;
331     if (fcntl(iop->fd, F_SETFL, flags) < 0)
332         return -1;
333     if (value == 0)
334         iop->flags &= ~IO_NBLOCK;
335     else
336         iop->flags |= IO_NBLOCK;
337     return 0;
338 }
339
340 int
341 io_error(struct iop *iop)
342 {
343     return iop->flags & IO_ERROR;
344 }
345
346 int
347 io_eof(struct iop *iop)
348 {
349     return iop->flags & IO_EOF;
350 }
351
352 int
353 io_fileno(struct iop *iop)
354 {
355     return iop->fd;
356 }