2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
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.
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.
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
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.
28 * io.c: Arrange for input and output on a file descriptor to be queued.
30 * Known contributors to this file:
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.
43 #include <sys/types.h>
47 #include <unistd.h> /* close read shutdown select */
48 #include <sys/socket.h>
52 #include <stdlib.h> /* malloc calloc free */
64 #include "gen.h" /* getfdtablesize */
66 #include "empthread.h"
68 extern struct player *player; /* XXX */
70 static struct iop **io_list;
71 static struct io_mask *iom;
72 static bit_fdmask newoutput;
76 struct ioqueue *input;
77 struct ioqueue *output;
89 iom = iom_create(IO_READ|IO_WRITE);
90 io_list = (struct iop **) calloc(getfdtablesize(), sizeof(*io_list));
91 newoutput = bit_newfdmask();
95 io_open(int fd, int flags, int bufsize, int (*notify) (void), s_char *assoc)
99 if (io_list[fd] != 0) {
103 flags = flags & (IO_READ|IO_WRITE|IO_NBLOCK|IO_NEWSOCK);
104 if ((flags & (IO_READ|IO_WRITE)) == 0)
106 iop = (struct iop *) malloc(sizeof(struct iop));
111 iop->bufsize = bufsize;
112 if ((flags & IO_READ) && (flags & IO_NEWSOCK) == 0)
113 iop->input = ioq_create(bufsize);
114 if ((flags & IO_WRITE) && (flags & IO_NEWSOCK) == 0)
115 iop->output = ioq_create(bufsize);
116 if (flags & IO_NBLOCK)
117 io_noblocking(iop, 1);
120 iop->notify = notify;
122 iom_set(iom, flags, fd);
127 io_close(struct iop *iop)
131 ioq_destroy(iop->input);
132 if (iop->output != 0)
133 ioq_destroy(iop->output);
134 iom_clear(iom, iop->flags, iop->fd);
135 BIT_CLRB(iop->fd, newoutput);
136 io_list[iop->fd] = 0;
138 (void) close(iop->fd);
140 closesocket(iop->fd);
146 io_input(struct iop *iop, int waitforinput)
148 s_char buf[IO_BUFSIZE];
152 if ((iop->flags & IO_READ) == 0)
154 /* IOP is markes as in error. */
155 if (iop->flags & IO_ERROR)
157 /* Wait for the file to have input. */
159 empth_select(iop->fd, EMPTH_FD_READ);
162 /* Do the actual read. */
163 cc = read(iop->fd, buf, sizeof(buf));
165 /* would block, so nothing to read. */
166 if (errno == EWOULDBLOCK)
169 /* Some form of file error occurred... */
170 iop->flags |= IO_ERROR;
171 iom_clear(iom, IO_READ, iop->fd);
175 cc = recv(iop->fd, buf, sizeof(buf), 0);
176 if (cc == SOCKET_ERROR) {
177 int err = WSAGetLastError();
178 /* Hmm, it would block. file is opened noblock, soooooo.. */
179 if (err == WSAEWOULDBLOCK)
182 /* Some form of file error occurred... */
183 iop->flags |= IO_ERROR;
184 iom_clear(iom, IO_READ, iop->fd);
191 iop->flags |= IO_EOF;
195 /* Append the input to the IOQ. */
196 ioq_append(iop->input, buf, cc);
201 io_inputwaiting(struct iop *iop)
203 return ioq_qsize(iop->input);
207 io_outputwaiting(struct iop *iop)
209 return ioq_qsize(iop->output);
213 io_output(struct iop *iop, int waitforoutput)
216 struct iovec iov[16];
218 s_char buf[IO_BUFSIZE];
224 /* If there is no output waiting. */
225 if (!io_outputwaiting(iop))
229 BIT_CLRB(iop->fd, newoutput);
231 /* If the iop is not write enabled. */
232 if ((iop->flags & IO_WRITE) == 0)
235 /* If the io is marked as in error... */
236 if (iop->flags & IO_ERROR)
239 /* This is the same test as io_outputwaiting.... */
240 if (ioq_qsize(iop->output) == 0)
244 /* make the iov point to the data in the queue. */
245 /* I.E., each of the elements in the queue. */
246 /* returns the number of elements in the iov. */
247 n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
249 /* Make a buffer containing the output to write. */
250 n = ioq_makebuf(iop->output, buf, sizeof(buf));
254 /* If we got no elements, we have no output.... */
255 iom_clear(iom, IO_WRITE, iop->fd);
259 /* wait for the file to be output ready. */
260 if (waitforoutput != IO_NOWAIT) {
261 /* This waits for the file to be ready for writing, */
262 /* and lets other threads run. */
263 empth_select(iop->fd, EMPTH_FD_WRITE);
266 /* Do the actual write. */
268 cc = writev(iop->fd, iov, n);
270 /* if it failed.... */
272 /* Hmm, it would block. file is opened noblock, soooooo.. */
273 if (errno == EWOULDBLOCK) {
274 /* If there are remaining bytes, set the IO as remaining.. */
275 remain = ioq_qsize(iop->output);
277 iom_set(iom, IO_WRITE, iop->fd);
280 iop->flags |= IO_ERROR;
281 iom_clear(iom, IO_WRITE, iop->fd);
285 cc = send(iop->fd, buf, n, 0);
287 /* if it failed.... */
288 if (cc == SOCKET_ERROR) {
289 int err = WSAGetLastError();
290 /* Hmm, it would block. file is opened noblock, soooooo.. */
291 if (err == WSAEWOULDBLOCK) {
292 /* If there are remaining bytes, set the IO as remaining.. */
293 remain = ioq_qsize(iop->output);
295 iom_set(iom, IO_WRITE, iop->fd);
298 iop->flags |= IO_ERROR;
299 iom_clear(iom, IO_WRITE, iop->fd);
305 /* If no bytes were written, something happened.. Like an EOF. */
308 iop->flags |= IO_EOF;
313 remain = ioq_qsize(iop->output);
315 iom_set(iom, IO_WRITE, iop->fd);
320 /* Remove the number of written bytes from the queue. */
321 ioq_dequeue(iop->output, cc);
323 /* If the queue has stuff remaining, set it still needing output. */
324 remain = ioq_qsize(iop->output);
326 iom_clear(iom, IO_WRITE, iop->fd);
328 iom_set(iom, IO_WRITE, iop->fd);
334 io_select(struct timeval *tv)
337 bit_fdmask writemask;
343 iom_getmask(iom, &nfds, &readmask, &writemask);
344 n = select(nfds + 1, (fd_set *)readmask, (fd_set *)writemask, 0, tv);
350 while ((fd = bit_fd(readmask)) >= 0) {
352 if ((iop->flags & IO_NEWSOCK) == 0)
353 (void) io_input(iop, IO_NOWAIT);
354 if (iop->notify != 0)
355 iop->notify(iop, IO_READ, iop->assoc);
356 BIT_CLRB(fd, readmask);
358 while ((fd = bit_fd(writemask)) >= 0) {
360 if (io_output(iop, IO_NOWAIT) < 0 && iop->notify != 0)
361 iop->notify(iop, IO_WRITE, iop->assoc);
362 BIT_CLRB(fd, writemask);
373 while ((fd = bit_fd(newoutput)) >= 0) {
375 if (io_output(iop, doWait) < 0 && iop->notify != 0)
376 iop->notify(iop, IO_WRITE, iop->assoc);
381 io_peek(struct iop *iop, s_char *buf, int nbytes)
383 if ((iop->flags & IO_READ) == 0)
385 return ioq_peek(iop->input, buf, nbytes);
389 io_read(struct iop *iop, s_char *buf, int nbytes)
393 if ((iop->flags & IO_READ) == 0)
395 cc = ioq_peek(iop->input, buf, nbytes);
397 ioq_dequeue(iop->input, cc);
402 io_write(struct iop *iop, s_char *buf, int nbytes, int doWait)
406 if ((iop->flags & IO_WRITE) == 0)
408 ioq_append(iop->output, buf, nbytes);
409 BIT_SETB(iop->fd, newoutput);
410 len = ioq_qsize(iop->output);
411 if (len > iop->bufsize) {
415 /* only try a write every BUFSIZE characters */
416 if (((len-nbytes) % iop->bufsize) <
417 (len % iop->bufsize))
425 io_output_all(struct iop *iop)
429 while ((n = io_output(iop, IO_NOWAIT)) > 0) {
430 empth_select(iop->fd, EMPTH_FD_WRITE);
436 io_gets(struct iop *iop, s_char *buf, int nbytes)
438 if ((iop->flags & IO_READ) == 0)
440 return ioq_gets(iop->input, buf, nbytes);
444 io_puts(struct iop *iop, s_char *buf)
446 if ((iop->flags & IO_WRITE) == 0)
448 BIT_SETB(iop->fd, newoutput);
449 return ioq_puts(iop->output, buf);
453 io_shutdown(struct iop *iop, int flags)
455 flags &= (IO_READ|IO_WRITE);
456 if ((iop->flags & flags) != flags)
458 if (flags & IO_READ) {
459 shutdown(iop->fd, 0);
460 ioq_drain(iop->input);
462 if (flags & IO_WRITE) {
463 shutdown(iop->fd, 1);
464 ioq_drain(iop->output);
470 io_noblocking(struct iop *iop, int value)
475 flags = fcntl(iop->fd, F_GETFL, 0);
482 if (fcntl(iop->fd, F_SETFL, flags) < 0)
486 ioctlsocket(iop->fd, FIONBIO, &arg);
489 iop->flags &= ~IO_NBLOCK;
491 iop->flags |= IO_NBLOCK;
496 io_conn(struct iop *iop)
498 return (iop->flags & IO_CONN);
502 io_error(struct iop *iop)
504 return (iop->flags & IO_ERROR);
508 io_eof(struct iop *iop)
510 return (iop->flags & IO_EOF);
514 io_fileno(struct iop *iop)