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