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
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 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.
28 * play.c: Playing the game
30 * Known contributors to this file:
31 * Markus Armbruster, 2007
42 #include <sys/types.h>
50 #define EOF_COOKIE "ctld\n"
51 #define INTR_COOKIE "\naborted\n"
54 int send_eof; /* need to send EOF_COOKIE */
55 static volatile sig_atomic_t send_intr; /* need to send INTR_COOKIE */
58 * Receive and process server output from SOCK.
59 * Return number of characters received on success, -1 on error.
65 * Read a chunk of server output and feed its characters into a
66 * simple state machine.
67 * Initial state is SCANNING_ID.
68 * In state SCANNING_ID, buffer the character. If it's a space,
69 * decode the id that has been buffered, and enter state BUFFERING
70 * or COPYING depending on its value.
71 * In state BUFFERING, buffer the character. If it's newline,
72 * pass id and buffered text to servercmd(), then enter state
74 * In state COPYING, pass the character to outch(). If it's
75 * newline, enter state SCANNING_ID.
78 SCANNING_ID, BUFFERING, COPYING
79 } state = SCANNING_ID;
81 static struct lbuf lbuf;
87 n = read(sock, buf, sizeof(buf));
91 for (i = 0; i < n; i++) {
96 /* FIXME gripe unexpected! */
101 lbuf_putc(&lbuf, ch);
104 line = lbuf_line(&lbuf);
105 id = strtol(line, &end, 16);
106 if (end == line || *end) {
107 /* FIXME gripe bad id */
124 /* unknown or unexpected id, treat like C_DATA */
132 len = lbuf_putc(&lbuf, ch);
134 line = lbuf_line(&lbuf);
135 servercmd(id, line, len);
152 * Receive command input from FD into INBUF.
153 * Return 1 on receipt of input, zero on EOF, -1 on error.
156 recv_input(int fd, struct ring *inbuf)
158 static struct lbuf cmdbuf;
163 n = ring_from_file(inbuf, fd);
168 if (lbuf_len(&cmdbuf)) {
169 /* incomplete line */
170 ring_putc(inbuf, '\n');
174 * Can't put EOF cookie into INBUF here, it may not fit.
175 * Leave it to caller.
180 /* copy input to AUXFP etc. */
181 for (i = -n; i < 0; i++) {
182 ch = ring_peek(inbuf, i);
184 if (lbuf_putc(&cmdbuf, ch)) {
185 line = lbuf_line(&cmdbuf);
201 signal(SIGINT, intr);
207 * The session must be in the playing phase.
208 * Return 0 when the session ended, -1 on error.
214 * Player input flows from INPUT_FD through recv_input() into ring
215 * buffer INBUF, which drains into SOCK. This must not block.
216 * Server output flows from SOCK into recv_output(). Reading SOCK
220 struct ring inbuf; /* input buffer, draining to SOCK */
221 int eof_fd0; /* read fd 0 hit EOF? */
226 sa.sa_handler = intr;
227 sigaction(SIGINT, &sa, NULL);
228 sa.sa_handler = SIG_IGN;
229 sigaction(SIGPIPE, &sa, NULL);
232 eof_fd0 = send_eof = send_intr = 0;
240 * Want to read player input only when we don't need to send
241 * cookies, and we haven't hit EOF on fd 0, and INBUF can
244 if (!send_intr && !send_eof && !eof_fd0 && ring_space(&inbuf))
245 FD_SET(input_fd, &rdfd);
246 /* Want to send player input only when we have something */
247 if (send_intr || send_eof || ring_len(&inbuf))
249 /* Always want to read server output */
252 n = select(MAX(input_fd, sock) + 1, &rdfd, &wrfd, NULL, NULL);
254 if (errno != EINTR) {
261 && ring_putm(&inbuf, EOF_COOKIE, sizeof(EOF_COOKIE) - 1) >= 0)
264 && ring_putm(&inbuf, INTR_COOKIE, sizeof(INTR_COOKIE) - 1) >= 0)
270 /* read player input */
271 if (FD_ISSET(input_fd, &rdfd)) {
272 n = recv_input(input_fd, &inbuf);
274 perror("read stdin"); /* FIXME stdin misleading, could be execing */
281 /* execute done, switch back to fd 0 */
285 /* stop reading input, drain socket ring buffers */
287 sa.sa_handler = SIG_DFL;
288 sigaction(SIGINT, &sa, NULL);
293 /* send it to the server */
294 if (FD_ISSET(sock, &wrfd)) {
295 n = ring_to_file(&inbuf, sock);
297 perror("write socket");
302 /* read server output and print it */
303 if (FD_ISSET(sock, &rdfd)) {
304 n = recv_output(sock);
306 perror("read socket");