]> git.pond.sub.org Git - empserver/commitdiff
Fix client not to hang when EOF on stdin overtakes C_EXECUTE
authorMarkus Armbruster <armbru@pond.sub.org>
Sun, 5 Apr 2009 08:58:30 +0000 (10:58 +0200)
committerMarkus Armbruster <armbru@pond.sub.org>
Sun, 5 Apr 2009 08:58:30 +0000 (10:58 +0200)
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

index 11ea847e9fe6626bff9bcaa85575200179dcd3a9..36631290a9cb5628a44b71da3310c005377eac48 100644 (file)
@@ -473,10 +473,10 @@ play(int sock)
 
        /*
         * Want to read player input only when we don't need to send
 
        /*
         * 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))
            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 */
            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 */
            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);
                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;
                } else {
                    /* stop reading input, drain socket ring buffers */
                    eof_fd0 = 1;
+                   input_fd = -1;
                    sa.sa_handler = SIG_DFL;
                    sigaction(SIGINT, &sa, NULL);
                }
                    sa.sa_handler = SIG_DFL;
                    sigaction(SIGINT, &sa, NULL);
                }