empserver/src/lib/player/recvclient.c
Markus Armbruster ca7578f1b8 Fix idle timeout during execute
Timeout during execute gets handled just like an EOF cookie: end the
batch file, resume reading normal commands.  That's wrong, we need to
close the connection.

A real EOF is recorded in the player's connection's EOF indicator.
Let's use that for all "connection needs to be closed" conditions, so
they all work the same.  Create io_set_eof() to provide access.

Make recvclient() set the player connection's EOF indicator on
timeout.  This makes the timeout "stick".  Record receipt of an EOF
cookie in new struct player member got_ctld.  Also abort the command,
as before.  This leaves further interpretation of the EOF cookie to
the command loops.

Make player_main() set the player connection's EOF indicator on
got_ctld.  Player connection gets closed on on EOF cookie, as before.

Change execute() to break the batch command loop when got_ctld is set,
then reset it.  Ends the batch file on EOF cookie, as before.

Change status() back to checking EOF and error indicators (partial
revert of commit 9c5854c8, v4.3.16), and drop struct player member
eof.
2012-02-21 18:10:52 +01:00

122 lines
3.5 KiB
C

/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure, Markus Armbruster
*
* Empire is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ---
*
* See files README, COPYING and CREDITS in the root of the source
* tree for related information and legal notices. It is expected
* that future projects/authors will amend these files as needed.
*
* ---
*
* recvclient.c: Receive input from the client
*
* Known contributors to this file:
* Dave Pare, 1986
* Markus Armbruster, 2006-2012
* Ron Koenderink, 2009
*/
#include <config.h>
#include "empio.h"
#include "journal.h"
#include "player.h"
#include "prototypes.h"
/*
* Receive a line of input from the current player.
* If the player's aborted flag is set, return -1 without receiving
* input.
* Else receive one line and store it in CMD[SIZE].
* This may block for input, yielding the processor. Flush buffered
* output when blocking, to make sure player sees the prompt.
* If the player's connection has the I/O error or EOF indicator set,
* or the line is "aborted", set the player's aborted flag and return
* -1.
* If we block and time out, set the EOF indicator on the player's
* connection, set the player's aborted flag, and return -1.
* If the line is "ctld", set the player's eof and aborted flag and
* return -1.
* Else return the length of the line.
* Design bug: there is no way to indicate truncation of a long line.
*/
int
recvclient(char *cmd, int size)
{
int count, res;
count = -1;
while (!player->aborted) {
/* Try to get a line of input */
count = io_gets(player->iop, cmd, size);
if (count >= 0) {
/* got it */
if (strcmp(cmd, "ctld") == 0)
player->aborted = player->got_ctld = 1;
if (strcmp(cmd, "aborted") == 0)
player->aborted = 1;
journal_input(cmd);
break;
}
/*
* Flush all queued output before potentially sleeping in
* io_input(), to make sure player sees the prompt.
*/
while (io_output(player->iop,
player->may_sleep >= PLAYER_SLEEP_ON_INPUT) > 0)
;
/*
* If io_output() blocked and got unblocked by command
* abortion, we must return without blocking in io_input().
*/
if (player->aborted)
break;
res = io_input(player->iop, 1);
if (res > 0)
;
else if (res < 0)
player->aborted = 1;
else if (io_eof(player->iop))
player->aborted = 1;
else if (!player->aborted) {
pr_flash(player, "idle connection terminated\n");
io_set_eof(player->iop);
player->aborted = 1;
}
}
if (player->aborted) {
player->recvfail++;
if (player->recvfail > 255) {
/*
* Looks like the thread is stuck in a loop that fails to
* check errors; oops once, then slow it down drastically.
*/
CANT_HAPPEN(player->recvfail == 256);
empth_sleep(time(NULL) + 60);
}
return -1;
}
player->recvfail = 0;
return count;
}