]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
ce226a0fc788fbcb03813ef912d0042072523a27
[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  *      Ron Koenderink, 2009
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/socket.h>
48 #include <sys/types.h>
49 #include <sys/uio.h>
50 #include <unistd.h>
51 #include "empio.h"
52 #include "empthread.h"
53 #include "file.h"
54 #include "ioqueue.h"
55 #include "misc.h"
56 #include "queue.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     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->last_out = 0;
98     iop->bufsize = bufsize;
99     iop->input_timeout = timeout;
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 void
108 io_close(struct iop *iop)
109 {
110
111     if (iop->input)
112         ioq_destroy(iop->input);
113     if (iop->output)
114         ioq_destroy(iop->output);
115     (void)close(iop->fd);
116     free(iop);
117 }
118
119 /*
120  * Return number of bytes read on success, zero on timeout, early
121  * wakeup or EOF, -1 on error, with errno set appropriately.  In
122  * particular, return -1 with errno set to EAGAIN or EWOULDBLOCK when
123  * no data is available for non-blocking input (WAITFORINPUT false).
124  * Use io_eof() to distinguish timeout and early wakeup from EOF.
125  */
126 int
127 io_input(struct iop *iop, int waitforinput)
128 {
129     char buf[IO_BUFSIZE];
130     int cc;
131     int res;
132
133     /* Not a read IOP */
134     if ((iop->flags & IO_READ) == 0) {
135         errno = EBADF;
136         return -1;
137     }
138     /* IOP is markes as in error. */
139     if (iop->flags & IO_ERROR) {
140         errno = EBADF;
141         return -1;
142     }
143     /* Wait for the file to have input. */
144     if (waitforinput) {
145         res = empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout);
146         if (res < 0) {
147             iop->flags |= IO_ERROR;
148             return -1;
149         } else if (res == 0)
150             return 0;
151     }
152
153     /* Do the actual read. */
154     cc = read(iop->fd, buf, sizeof(buf));
155     if (cc < 0) {
156         if (errno != EAGAIN && errno != EWOULDBLOCK)
157             /* Some form of file error occurred... */
158             iop->flags |= IO_ERROR;
159         return -1;
160     }
161
162     /* We eof'd */
163     if (cc == 0) {
164         iop->flags |= IO_EOF;
165         return 0;
166     }
167
168     /* Append the input to the IOQ. */
169     ioq_append(iop->input, buf, cc);
170     return cc;
171 }
172
173 int
174 io_inputwaiting(struct iop *iop)
175 {
176     return ioq_qsize(iop->input);
177 }
178
179 int
180 io_outputwaiting(struct iop *iop)
181 {
182     return ioq_qsize(iop->output);
183 }
184
185 /*
186  * Write output queued in IOP.
187  * If WAIT, writing may put the thread to sleep.
188  * Return number of bytes written on success, -1 on error.
189  * In particular, return zero when nothing was written because the
190  * queue was empty, or because the write slept and got woken up (only
191  * if WAIT), or because the write refused to sleep (only if !WAIT).
192  */
193 int
194 io_output(struct iop *iop, int wait)
195 {
196     struct iovec iov[16];
197     int n, res, cc;
198
199     if (wait)
200         ef_make_stale();
201
202     if (!ioq_qsize(iop->output))
203         return 0;
204
205     if ((iop->flags & IO_WRITE) == 0)
206         return -1;
207
208     if (iop->flags & IO_ERROR)
209         return -1;
210
211     if (wait) {
212         res = empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
213         if (res == 0)
214             return 0;
215         if (res < 0) {
216             iop->flags |= IO_ERROR;
217             return -1;
218         }
219     }
220
221     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
222     cc = writev(iop->fd, iov, n);
223     if (cc < 0) {
224         if (errno == EAGAIN || errno == EWOULDBLOCK)
225             return 0;
226         iop->flags |= IO_ERROR;
227         return -1;
228     }
229
230     ioq_dequeue(iop->output, cc);
231     iop->last_out = ioq_qsize(iop->output);
232     return cc;
233 }
234
235 /*
236  * Write output queued in IOP if enough have been enqueued.
237  * Write if at least one buffer has been filled since the last write.
238  * If WAIT, writing may put the thread to sleep.
239  * Return number of bytes written on success, -1 on error.
240  * In particular, return zero when nothing was written because the
241  * queue was not long, or the write slept and got woken up (only if
242  * WAIT), or the write refused to sleep (only if !WAIT).
243  */
244 int
245 io_output_if_queue_long(struct iop *iop, int wait)
246 {
247     int len = ioq_qsize(iop->output);
248
249     if (CANT_HAPPEN(iop->last_out > len))
250         iop->last_out = 0;
251     if (len - iop->last_out < iop->bufsize) {
252         if (wait)
253             ef_make_stale();
254         return 0;
255     }
256     return io_output(iop, wait);
257 }
258
259
260 int
261 io_peek(struct iop *iop, char *buf, int nbytes)
262 {
263     if ((iop->flags & IO_READ) == 0)
264         return -1;
265     return ioq_peek(iop->input, buf, nbytes);
266 }
267
268 int
269 io_read(struct iop *iop, char *buf, int nbytes)
270 {
271     int cc;
272
273     if ((iop->flags & IO_READ) == 0)
274         return -1;
275     cc = ioq_peek(iop->input, buf, nbytes);
276     if (cc > 0)
277         ioq_dequeue(iop->input, cc);
278     return cc;
279 }
280
281 int
282 io_write(struct iop *iop, char *buf, int nbytes)
283 {
284     if ((iop->flags & IO_WRITE) == 0)
285         return -1;
286     ioq_append(iop->output, buf, nbytes);
287     return nbytes;
288 }
289
290 int
291 io_gets(struct iop *iop, char *buf, int nbytes)
292 {
293     if ((iop->flags & IO_READ) == 0)
294         return -1;
295     return ioq_gets(iop->input, buf, nbytes);
296 }
297
298 int
299 io_puts(struct iop *iop, char *buf)
300 {
301     if ((iop->flags & IO_WRITE) == 0)
302         return -1;
303     return ioq_puts(iop->output, buf);
304 }
305
306 int
307 io_shutdown(struct iop *iop, int flags)
308 {
309     flags &= (IO_READ | IO_WRITE);
310     if ((iop->flags & flags) != flags)
311         return -1;
312     if (flags & IO_READ) {
313         shutdown(iop->fd, 0);
314         ioq_drain(iop->input);
315     }
316     if (flags & IO_WRITE) {
317         shutdown(iop->fd, 1);
318         ioq_drain(iop->output);
319         iop->last_out = 0;
320     }
321     return 0;
322 }
323
324 int
325 io_error(struct iop *iop)
326 {
327     return iop->flags & IO_ERROR;
328 }
329
330 int
331 io_eof(struct iop *iop)
332 {
333     return iop->flags & IO_EOF;
334 }
335
336 int
337 io_fileno(struct iop *iop)
338 {
339     return iop->fd;
340 }