From 2196ffd55c869505f63f3d806c3f7475b52ae12d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 5 Apr 2009 10:58:30 +0200 Subject: [PATCH] Fix client not to hang when EOF on stdin overtakes C_EXECUTE Player input may overtake batch file contents (well-known protocol flaw, see doc/clients-howto for details). This includes EOF. When that happens, the client closes standard input, sends an EOF cookie, and continues reading output until the server closes the connection. When it gets C_EXECUTE, it redirects input to the batch file. But it then failed to read the batch file. The server waited forever for the execute's EOF cookie, the client waited forever for the server closing the connection. Fix by stopping only reading from standard input. Broken in 8b7d0b91, v4.3.11. Note that the EOF cookie still overtakes the batch file contents, which makes the server interpret the input between the execute command and the EOF as batch file, and the batch file contents as ordinary input. --- src/client/play.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/client/play.c b/src/client/play.c index 11ea847e..36631290 100644 --- a/src/client/play.c +++ b/src/client/play.c @@ -473,10 +473,10 @@ play(int sock) /* * Want to read player input only when we don't need to send - * cookies, and we haven't hit EOF on fd 0, and INBUF can - * accept some. + * cookies, and INPUT_FD is still open, and INBUF can accept + * some. */ - if (!send_intr && !send_eof && !eof_fd0 && ring_space(&inbuf)) + if (!send_intr && !send_eof && input_fd >= 0 && ring_space(&inbuf)) FD_SET(input_fd, &rdfd); /* Want to send player input only when we have something */ if (send_intr || send_eof || ring_len(&inbuf)) @@ -503,7 +503,7 @@ play(int sock) continue; /* read player input */ - if (FD_ISSET(input_fd, &rdfd)) { + if (input_fd >= 0 && FD_ISSET(input_fd, &rdfd)) { n = recv_input(input_fd, &inbuf); if (n < 0) { perror("read stdin"); /* FIXME stdin misleading, could be execing */ @@ -515,10 +515,11 @@ play(int sock) if (input_fd) { /* execute done, switch back to fd 0 */ close(input_fd); - input_fd = 0; + input_fd = eof_fd0 ? -1 : 0; } else { /* stop reading input, drain socket ring buffers */ eof_fd0 = 1; + input_fd = -1; sa.sa_handler = SIG_DFL; sigaction(SIGINT, &sa, NULL); }