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