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