1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, 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  *     Markus Armbruster, 2004-2012
33  *     Ron Koenderink, 2009
34  */
35 
36 /*
37  * Arrange for input and output on a file descriptor
38  * to be queued.  Provide main loop -- a mechanism for
39  * blocking across all registered file descriptors, and
40  * reading or writing when appropriate.
41  */
42 
43 #include <config.h>
44 
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include <sys/socket.h>
49 #include <sys/types.h>
50 #include <sys/uio.h>
51 #include <unistd.h>
52 #include "empio.h"
53 #include "empthread.h"
54 #include "file.h"
55 #include "ioqueue.h"
56 #include "misc.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 };
66 
67 static struct timeval *io_timeout(struct timeval *, time_t);
68 
69 void
io_init(void)70 io_init(void)
71 {
72 }
73 
74 struct iop *
io_open(int fd,int flags,int bufsize)75 io_open(int fd, int flags, int bufsize)
76 {
77     int fdfl;
78     struct iop *iop;
79 
80     flags = flags & (IO_READ | IO_WRITE);
81     if ((flags & (IO_READ | IO_WRITE)) == 0)
82 	return NULL;
83 
84     fdfl = fcntl(fd, F_GETFL, 0);
85     if (fdfl < 0)
86 	return NULL;
87     fdfl |= O_NONBLOCK;
88     if (fcntl(fd, F_SETFL, fdfl) < 0)
89 	return NULL;
90 
91     iop = malloc(sizeof(struct iop));
92     if (!iop)
93 	return NULL;
94     iop->fd = fd;
95     iop->input = NULL;
96     iop->output = NULL;
97     iop->flags = flags;
98     iop->last_out = 0;
99     iop->bufsize = bufsize;
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 /*
108  * Close @iop.
109  * Flush output and wait for the client to close the connection.
110  * Wait at most until @deadline.  (time_t)-1 means wait as long as it
111  * takes (no timeout).
112  * Both the flush and the wait can be separately cut short by
113  * empth_wakeup().  This is almost certainly not what you want.  If
114  * you need early wakeup, better fix this function not to go to sleep
115  * after wakeup during flush.
116  */
117 void
io_close(struct iop * iop,time_t deadline)118 io_close(struct iop *iop, time_t deadline)
119 {
120     struct timeval timeout;
121     char buf[IO_BUFSIZE];
122     int ret;
123 
124     while (io_output(iop, deadline) > 0) ;
125     shutdown(iop->fd, SHUT_WR);
126     while (empth_select(iop->fd, EMPTH_FD_READ,
127 			io_timeout(&timeout, deadline)) > 0) {
128 	ret = read(iop->fd, buf, sizeof(buf));
129 	if (ret <= 0)
130 	    break;
131     }
132     if (iop->input)
133 	ioq_destroy(iop->input);
134     if (iop->output)
135 	ioq_destroy(iop->output);
136     (void)close(iop->fd);
137     free(iop);
138 }
139 
140 static struct timeval *
io_timeout(struct timeval * timeout,time_t deadline)141 io_timeout(struct timeval *timeout, time_t deadline)
142 {
143     struct timeval now;
144 
145     if (deadline == (time_t)-1)
146 	return NULL;		/* no deadline */
147 
148     gettimeofday(&now, NULL);
149     if (now.tv_sec >= deadline) {
150 	/* deadline reached already */
151 	timeout->tv_sec = 0;
152 	timeout->tv_usec = 0;
153     } else {
154 	/* deadline in future */
155 	timeout->tv_sec = deadline - now.tv_sec - 1;
156 	timeout->tv_usec = 999999 - now.tv_usec;
157 	/* yes, this is 1usec early; sue me */
158     }
159 
160     return timeout;
161 }
162 
163 /*
164  * Read input from @iop and enqueue it.
165  * Wait at most until @deadline for input to arrive.  (time_t)-1 means
166  * wait as long as it takes (no timeout).
167  * Does not yield the processor when @deadline is zero.
168  * A wait for input can be cut short by empth_wakeup().
169  * Return number of bytes read on success, -1 on error.
170  * In particular, return zero on timeout, early wakeup or EOF.  Use
171  * io_eof() to distinguish timeout and early wakeup from EOF.
172  */
173 int
io_input(struct iop * iop,time_t deadline)174 io_input(struct iop *iop, time_t deadline)
175 {
176     struct timeval timeout;
177     char buf[IO_BUFSIZE];
178     int cc;
179     int res;
180 
181     if ((iop->flags & IO_READ) == 0)
182 	return -1;
183     if (iop->flags & IO_ERROR)
184 	return -1;
185     if (iop->flags & IO_EOF)
186 	return 0;
187 
188     if (deadline) {
189 	res = empth_select(iop->fd, EMPTH_FD_READ,
190 			   io_timeout(&timeout, deadline));
191 	if (res < 0) {
192 	    iop->flags |= IO_ERROR;
193 	    return -1;
194 	} else if (res == 0)
195 	    return 0;
196     }
197 
198     cc = read(iop->fd, buf, sizeof(buf));
199     if (cc < 0) {
200 	if (errno == EAGAIN || errno == EWOULDBLOCK)
201 	    return 0;
202 	iop->flags |= IO_ERROR;
203 	return -1;
204     }
205     if (cc == 0) {
206 	iop->flags |= IO_EOF;
207 	return 0;
208     }
209 
210     ioq_append(iop->input, buf, cc);
211     return cc;
212 }
213 
214 int
io_inputwaiting(struct iop * iop)215 io_inputwaiting(struct iop *iop)
216 {
217     return ioq_qsize(iop->input);
218 }
219 
220 int
io_outputwaiting(struct iop * iop)221 io_outputwaiting(struct iop *iop)
222 {
223     return ioq_qsize(iop->output);
224 }
225 
226 /*
227  * Write output queued in @iop.
228  * Wait at most until @deadline for input to arrive.  (time_t)-1 means
229  * wait as long as it takes (no timeout).
230  * Does not yield the processor when @deadline is zero.
231  * A wait for output can be cut short by empth_wakeup().
232  * Return number of bytes written on success, -1 on error.
233  * In particular, return zero when nothing was written because the
234  * queue is empty, and on timeout or early wakeup.  Use
235  * io_outputwaiting() to distinguish timeout and early wakeup from
236  * empty queue.
237  */
238 int
io_output(struct iop * iop,time_t deadline)239 io_output(struct iop *iop, time_t deadline)
240 {
241     struct timeval timeout;
242     struct iovec iov[16];
243     int n, res, cc;
244 
245     if (deadline)
246 	ef_make_stale();
247 
248     if ((iop->flags & IO_WRITE) == 0)
249 	return -1;
250 
251     if (iop->flags & IO_ERROR)
252 	return -1;
253 
254     if (!ioq_qsize(iop->output))
255 	return 0;
256 
257     if (deadline) {
258 	res = empth_select(iop->fd, EMPTH_FD_WRITE,
259 			   io_timeout(&timeout, deadline));
260 	if (res == 0)
261 	    return 0;
262 	if (res < 0) {
263 	    iop->flags |= IO_ERROR;
264 	    return -1;
265 	}
266     }
267 
268     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
269     cc = writev(iop->fd, iov, n);
270     if (cc < 0) {
271 	if (errno == EAGAIN || errno == EWOULDBLOCK)
272 	    return 0;
273 	iop->flags |= IO_ERROR;
274 	return -1;
275     }
276 
277     ioq_dequeue(iop->output, cc);
278     iop->last_out = ioq_qsize(iop->output);
279     return cc;
280 }
281 
282 /*
283  * Write output queued in @iop if enough have been enqueued.
284  * Write if at least one buffer has been filled since the last write.
285  * Wait at most until @deadline for output to be accepted.  (time_t)-1
286  * means wait as long as it takes (no timeout).
287  * Does not yield the processor when @deadline is zero.
288  * A wait for output can be cut short by empth_wakeup().
289  * Return number of bytes written on success, -1 on error.
290  * In particular, return zero when nothing was written because the
291  * queue isn't long, and on timeout or early wakeup.
292  */
293 int
io_output_if_queue_long(struct iop * iop,time_t deadline)294 io_output_if_queue_long(struct iop *iop, time_t deadline)
295 {
296     int len = ioq_qsize(iop->output);
297 
298     if (CANT_HAPPEN(iop->last_out > len))
299 	iop->last_out = 0;
300     if (len - iop->last_out < iop->bufsize) {
301 	if (deadline)
302 	    ef_make_stale();
303 	return 0;
304     }
305     return io_output(iop, deadline);
306 }
307 
308 int
io_peek(struct iop * iop,char * buf,int nbytes)309 io_peek(struct iop *iop, char *buf, int nbytes)
310 {
311     if ((iop->flags & IO_READ) == 0)
312 	return -1;
313     return ioq_peek(iop->input, buf, nbytes);
314 }
315 
316 int
io_read(struct iop * iop,char * buf,int nbytes)317 io_read(struct iop *iop, char *buf, int nbytes)
318 {
319     int cc;
320 
321     if ((iop->flags & IO_READ) == 0)
322 	return -1;
323     cc = ioq_peek(iop->input, buf, nbytes);
324     if (cc > 0)
325 	ioq_dequeue(iop->input, cc);
326     return cc;
327 }
328 
329 int
io_write(struct iop * iop,char * buf,int nbytes)330 io_write(struct iop *iop, char *buf, int nbytes)
331 {
332     if ((iop->flags & IO_WRITE) == 0)
333 	return -1;
334     ioq_append(iop->output, buf, nbytes);
335     return nbytes;
336 }
337 
338 int
io_gets(struct iop * iop,char * buf,int nbytes)339 io_gets(struct iop *iop, char *buf, int nbytes)
340 {
341     if ((iop->flags & IO_READ) == 0)
342 	return -1;
343     return ioq_gets(iop->input, buf, nbytes);
344 }
345 
346 int
io_puts(struct iop * iop,char * buf)347 io_puts(struct iop *iop, char *buf)
348 {
349     if ((iop->flags & IO_WRITE) == 0)
350 	return -1;
351     return ioq_puts(iop->output, buf);
352 }
353 
354 int
io_error(struct iop * iop)355 io_error(struct iop *iop)
356 {
357     return iop->flags & IO_ERROR;
358 }
359 
360 int
io_eof(struct iop * iop)361 io_eof(struct iop *iop)
362 {
363     return iop->flags & IO_EOF;
364 }
365 
366 /*
367  * Discard @iop's buffered input and set its EOF flag.
368  * No more input can be read from @iop.
369  */
370 void
io_set_eof(struct iop * iop)371 io_set_eof(struct iop *iop)
372 {
373     ioq_drain(iop->input);
374     iop->flags |= IO_EOF;
375 }
376 
377 int
io_fileno(struct iop * iop)378 io_fileno(struct iop *iop)
379 {
380     return iop->fd;
381 }
382