Rewrite much of client's playing phase code:
(EOF_COOKIE, INTR_COOKIE, input_fd, send_intr, recv_output) (recv_input, intr, play): New playing phase code. No native Windows support yet. Sends just one EOF cookie on EOF on standard input instead of up to three. Old servers (before recvclient.c rev. 1.16) fail to terminate the session when they receive an EOF cookie at an argument prompt. The session then hangs; use SIGINT to get out. No longer blocks on sending input, which could deadlock the session. Closes #827090. Fixes error handling for select(). Fixes race condition that could cause server output to be discarded on EOF on standard input. (main): Replace old playing phase code by a call to play(). (intr, sock, interrupt, handleintr): Replaced by play(), remove. [_WIN32] (hStdIn): Ditto. (auxfp): New. (servercmd, prompt, doexecute): Remove parameter auxfi, use auxfp. (eight_bit_clean): Move to servcmd.c. (servercmd): Work on a single non-C_DATA line instead of getting lines from an ioqueue. (servercmd, output, screen, outch): Deal with all ids in servercmd() rather than some there and some in output(). Don't treat C_NOECHO, C_ABORT, C_CMDERR, C_BADCMD specially. Fix C_FLASH and C_EXIT to ignore redirections; they used to ignore them only for some parts. Replace output() by outch(), fold screen into outch(). (servercmd): Truncate long prompts and telegram infos to prevent buffer overflow. (prompt): Use new parameters code, prompt, teles instead of global variables mode, the_prompt, num_teles. (num_teles, the_prompt, mode, nbtu, nmin): Remove. (prompt): Don't write an empty line before argument prompts to auxfp. (servercmd): Don't strip newline from redirections and execute, doredir(), dopipe() and doexecute() need it now. (doredir, dopipe, doexecute): Use new seen_input() instead of gettag(). (doexecute): Set input_fd and leave reading the script file to play(). (serverio, termio, sendeof): Replaced by play(), remove. (LBUF_LEN_MAX, lbuf, lbuf_init, lbuf_len, lbuf_full, lbuf_line) (lbuf_putc): New. (RING_SIZE, ring, ring_init, ring_len, ring_space, ring_peek) (ring_getc, ring_putc, ring_putm, ring_discard, ring_search) (ring_from_file, ring_to_file): New. (clear_recent_input, save_input, seen_input): New. (MAX): New. (ioqueue, io, ioq_init, ioq_dequeue, ioq_read, ioq_write, ioq_qsize) (ioq_drain, ioq_gets, ioqtobuf, enqueuecc, dequeuecc): Unused, remove. (QEMPTY, qelem, insque, remque, initque): Unused, remove. (tagstruct, taglist, io_init, gettag): Unused, remove.
This commit is contained in:
parent
2444a5c63a
commit
8b7d0b915d
15 changed files with 862 additions and 1127 deletions
245
src/client/ringbuf.c
Normal file
245
src/client/ringbuf.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure
|
||||
*
|
||||
* This program 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* ringbuf.c: Simple ring buffer
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include "ringbuf.h"
|
||||
|
||||
/*
|
||||
* Initialize empty ring buffer.
|
||||
* Not necessary if *R is already zeroed.
|
||||
*/
|
||||
void
|
||||
ring_init(struct ring *r)
|
||||
{
|
||||
r->cons = r->prod = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return number of bytes held in ring buffer.
|
||||
*/
|
||||
int
|
||||
ring_len(struct ring *r)
|
||||
{
|
||||
assert(r->prod - r->cons <= RING_SIZE);
|
||||
return r->prod - r->cons;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return how much space is left in ring buffer.
|
||||
*/
|
||||
int
|
||||
ring_space(struct ring *r)
|
||||
{
|
||||
return RING_SIZE - (r->prod - r->cons);
|
||||
}
|
||||
|
||||
/*
|
||||
* Peek at ring buffer contents.
|
||||
* N must be between -RING_SIZE-1 and RING_SIZE.
|
||||
* If N>=0, peek at the (N+1)-th byte to be gotten.
|
||||
* If N<0, peek at the -N-th byte that has been put in.
|
||||
* Return the byte as unsigned char coverted to int, or EOF if there
|
||||
* aren't that many bytes in the ring buffer.
|
||||
*/
|
||||
int
|
||||
ring_peek(struct ring *r, int n)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
assert(-RING_SIZE - 1 <= n && n <= RING_SIZE);
|
||||
|
||||
idx = n >= 0 ? r->cons + n : r->prod - -n;
|
||||
if (idx < r->cons && idx >= r->prod)
|
||||
return EOF;
|
||||
return r->buf[idx % RING_SIZE];
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and remove the oldest byte from the ring buffer.
|
||||
* Return it as unsigned char coverted to int, or EOF if the buffer was
|
||||
* empty.
|
||||
*/
|
||||
int
|
||||
ring_getc(struct ring *r)
|
||||
{
|
||||
if (r->cons == r->prod)
|
||||
return EOF;
|
||||
return r->buf[r->cons++ % RING_SIZE];
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to put byte C into the ring buffer.
|
||||
* Return EOF when the buffer is full, else C.
|
||||
*/
|
||||
int
|
||||
ring_putc(struct ring *r, unsigned char c)
|
||||
{
|
||||
if (r->prod - r->cons == RING_SIZE)
|
||||
return EOF;
|
||||
return r->buf[r->prod++ % RING_SIZE] = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to put SZ bytes from BUF into the ring buffer.
|
||||
* Return space left in ring buffer when it fits, else don't change
|
||||
* the ring buffer and return how much space is missing.
|
||||
*/
|
||||
int
|
||||
ring_putm(struct ring *r, void *buf, size_t sz)
|
||||
{
|
||||
char *p = buf;
|
||||
int left = ring_space(r) - sz;
|
||||
int res;
|
||||
size_t i;
|
||||
|
||||
if (left >= 0) {
|
||||
res = 0;
|
||||
for (i = 0; i < sz; i++)
|
||||
res = ring_putc(r, p[i]);
|
||||
assert(res != EOF);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard the N oldest bytes from the ring buffer.
|
||||
* It must hold at least that many.
|
||||
*/
|
||||
void
|
||||
ring_discard(struct ring *r, int n)
|
||||
{
|
||||
assert(n <= ring_len(r));
|
||||
r->cons += n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the ring buffer for zero-terminated string S.
|
||||
* If found, return a non-negative value referring to the beginning of
|
||||
* S in the buffer when passed to ring_peek(). Else return -1.
|
||||
*/
|
||||
int
|
||||
ring_search(struct ring *r, char *s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t i, j;
|
||||
|
||||
for (i = r->cons; i + len <= r->prod; i++) {
|
||||
for (j = 0; j < len && s[j] == r->buf[(i + j) % RING_SIZE]; j++) ;
|
||||
if (!s[j])
|
||||
return i - r->cons;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill ring buffer from file referred by file descriptor FD.
|
||||
* If ring buffer is already full, do nothing and return 0.
|
||||
* Else attempt to read as many bytes as space permits, with readv(),
|
||||
* and return its value.
|
||||
*/
|
||||
int
|
||||
ring_from_file(struct ring *r, int fd)
|
||||
{
|
||||
unsigned cons = r->cons % RING_SIZE;
|
||||
unsigned prod = r->prod % RING_SIZE;
|
||||
struct iovec iov[2];
|
||||
int cnt;
|
||||
ssize_t res;
|
||||
|
||||
if (r->prod == r->cons + RING_SIZE)
|
||||
return 0;
|
||||
|
||||
iov[0].iov_base = r->buf + prod;
|
||||
if (cons <= prod) {
|
||||
/* r->buf[prod..] */
|
||||
iov[0].iov_len = RING_SIZE - prod;
|
||||
/* r->buf[..cons-1] */
|
||||
iov[1].iov_base = r->buf;
|
||||
iov[1].iov_len = cons;
|
||||
cnt = 2;
|
||||
} else {
|
||||
/* r->buf[prod..cons-1] */
|
||||
iov[0].iov_len = cons - prod;
|
||||
cnt = 1;
|
||||
}
|
||||
res = readv(fd, iov, cnt);
|
||||
if (res < 0)
|
||||
return res;
|
||||
r->prod += res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drain ring buffer to file referred by file descriptor FD.
|
||||
* If ring buffer is already empty, do nothing and return 0.
|
||||
* Else attempt to write complete contents with writev(), and return
|
||||
* its value.
|
||||
*/
|
||||
int
|
||||
ring_to_file(struct ring *r, int fd)
|
||||
{
|
||||
unsigned cons = r->cons % RING_SIZE;
|
||||
unsigned prod = r->prod % RING_SIZE;
|
||||
struct iovec iov[2];
|
||||
int cnt;
|
||||
ssize_t res;
|
||||
|
||||
if (r->cons == r->prod)
|
||||
return 0;
|
||||
|
||||
iov[0].iov_base = r->buf + cons;
|
||||
if (prod <= cons) {
|
||||
/* r->buf[cons..] */
|
||||
iov[0].iov_len = RING_SIZE - cons;
|
||||
/* r->buf[..prod-1] */
|
||||
iov[1].iov_base = r->buf;
|
||||
iov[1].iov_len = prod;
|
||||
cnt = 2;
|
||||
} else {
|
||||
/* r->buf[cons..prod-1] */
|
||||
iov[0].iov_len = prod - cons;
|
||||
cnt = 1;
|
||||
}
|
||||
res = writev(fd, iov, cnt);
|
||||
if (res < 0)
|
||||
return res;
|
||||
r->cons += res;
|
||||
return res;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue