client: Fix obscure readline hang

If recv_input() can't stuff the whole line into @inbuf, it leaves its
tail in @input_from_rl.  If send_input() then empties @inbuf, the next
iteration will select @input_fd for reading instead of @sock for
writing, because @inbuf is empty.  Since @has_rl_input is still set,
recv_input() will do nothing, and the client hangs.

Fix as follows.  Factor ring_from_rl() out of recv_input().  Also call
it in send_input() to refill @inbuf from @input_from_rl.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
Markus Armbruster 2016-11-06 17:05:19 +01:00
parent 0cb6690600
commit 5e82836e3a

View file

@ -451,6 +451,32 @@ input_handler(char *line)
add_history(line);
#endif /* HAVE_READLINE_HISTORY */
}
static int
ring_from_rl(struct ring *inbuf)
{
size_t len;
int n;
assert(has_rl_input && input_from_rl);
len = strlen(input_from_rl);
n = ring_space(inbuf);
assert(n);
if (len >= (size_t)n) {
ring_putm(inbuf, input_from_rl, n);
memmove(input_from_rl, input_from_rl + n, len - n + 1);
} else {
ring_putm(inbuf, input_from_rl, len);
ring_putc(inbuf, '\n');
free(input_from_rl);
has_rl_input = 0;
n = len + 1;
}
return n;
}
#endif /* HAVE_LIBREADLINE */
/*
@ -462,28 +488,15 @@ recv_input(int fd, struct ring *inbuf)
{
int n;
int res = 1;
#ifdef HAVE_LIBREADLINE
size_t len;
#ifdef HAVE_LIBREADLINE
if (fd == 0) {
if (!has_rl_input)
rl_callback_read_char();
if (!has_rl_input)
return 1;
if (input_from_rl) {
len = strlen(input_from_rl);
n = ring_space(inbuf);
assert(n);
if (len >= (size_t)n) {
ring_putm(inbuf, input_from_rl, n);
memmove(input_from_rl, input_from_rl + n, len - n + 1);
} else {
ring_putm(inbuf, input_from_rl, len);
ring_putc(inbuf, '\n');
free(input_from_rl);
has_rl_input = 0;
n = len + 1;
}
n = ring_from_rl(inbuf);
} else
n = 0;
} else
@ -524,6 +537,11 @@ send_input(int fd, struct ring *inbuf)
putc(ch, auxfp);
}
#ifdef HAVE_LIBREADLINE
if (fd == 0 && has_rl_input && input_from_rl)
ring_from_rl(inbuf);
#endif
return res;
}