summaryrefslogtreecommitdiffstats
path: root/lib/vty_io_term.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vty_io_term.c')
-rw-r--r--lib/vty_io_term.c489
1 files changed, 271 insertions, 218 deletions
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 857e457a..61f35761 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -54,16 +54,9 @@
* is closed either on command, or on timeout, or when the daemon is reset
* or terminated.
*
- *
- *
- *
+ * All VIN_TERM and VOUT_TERM I/O is non-blocking.
*/
-
-
-
-
-
/*==============================================================================
* If possible, will use getaddrinfo() to find all the things to listen on.
*/
@@ -77,20 +70,26 @@
* Opening and closing VTY_TERMINAL type
*/
-typedef enum {
- utw_error = 0,
- utw_done = BIT(0), /* all possible is done */
- utw_stopped = BIT(1),
- utw_blocked = BIT(2), /* I/O blocked */
- utw_paused = utw_blocked | utw_stopped,
-} utw_ret_t ;
-
static void uty_term_read_ready(vio_vfd vfd, void* action_info) ;
static void uty_term_write_ready(vio_vfd vfd, void* action_info) ;
static vty_timer_time uty_term_read_timeout(vio_timer timer,
void* action_info) ;
static vty_timer_time uty_term_write_timeout(vio_timer timer,
void* action_info) ;
+
+typedef enum { /* see uty_term_write() */
+ utw_null = 0,
+
+ utw_error,
+
+ utw_done,
+
+ utw_blocked,
+ utw_paused,
+ utw_more_enter,
+
+} utw_ret_t ;
+
static utw_ret_t uty_term_write(vio_vf vf) ;
static void uty_term_will_echo(vty_cli cli) ;
@@ -162,11 +161,11 @@ uty_term_open(int sock_fd, union sockunion *su)
0) ; /* no ibuf required */
uty_vout_push(vio, vf, VOUT_TERM, uty_term_write_ready,
uty_term_write_timeout,
- 4096) ; /* obuf is required */
-
- uty_vout_sync_depth(vio) ; /* vin & vout are at same level */
+ 4096, /* obuf is required */
+ true) ; /* after buddy vin */
- vf->read_timeout = host.vty_timeout_val ; /* current EXEC timeout */
+ vf->read_timeout = host.vty_timeout_val ; /* current EXEC timeout */
+ vf->write_timeout = 30 ; /* something reasonable */
/* Set up the CLI object & initialise */
vf->cli = uty_cli_new(vf) ;
@@ -194,25 +193,33 @@ uty_term_open(int sock_fd, union sockunion *su)
vty_out(vty, "%% Cannot continue because no password is set\n") ;
/* Enter the command loop. */
- uty_cmd_loop_enter(vio) ;
+ uty_cmd_queue_loop_enter(vio) ;
} ;
/*------------------------------------------------------------------------------
- * Command line fetch from a VTY_TERMINAL.
+ * Command line fetch from a VTY_TERMINAL -- in vf_open state.
*
* Fetching a command line <=> the previous command has completed.
*
- * Returns: CMD_SUCCESS -- have another command line ready to go
- * CMD_WAITING -- would not wait for input <=> non-blocking
- * CMD_EOF -- ??????
+ * Returns: CMD_SUCCESS -- have another command line ready to go
+ * or: CMD_WAITING -- would not wait for input
*
* This can be called in any thread.
*
- * NB: this does not signal CMD_EOF TODO ????
+ * Note that does not signal CMD_EOF because that is handled for the
+ * VTY_TERMINAL by the cmd_do_eof "special command".
+ *
+ * Note that this does no actual I/O, all that is done in the pselect() process,
+ * while a command line is collected in the CLI. So does not here return
+ * CMD_IO_ERROR -- any errors are dealt with by signalling the command loop.
*/
extern cmd_return_code_t
uty_term_fetch_command_line(vio_vf vf, cmd_action action, cmd_context context)
{
+ VTY_ASSERT_LOCKED() ;
+
+ qassert(vf->vin_state == vf_open) ;
+
return uty_cli_want_command(vf->cli, action, context) ;
} ;
@@ -243,14 +250,18 @@ uty_term_show_error_context(vio_vf vf, vio_fifo ebuf, uint depth)
} ;
/*------------------------------------------------------------------------------
- * Push output to the terminal.
+ * Push output to the terminal -- always not vf->blocking !
*
- * Returns: CMD_SUCCESS -- all buffers are empty
- * CMD_WAITING -- all buffers are not empty
- * CMD_IO_ERROR -- failed -- final or not.
+ * Returns: CMD_SUCCESS -- done everything possible
+ * CMD_WAITING -- not "final" => waiting for output to complete
+ * "final" => would have waited but did not.
+ * CMD_IO_ERROR -- error or time-out (may be "final")
+ *
+ * This can be called in any thread.
*
- * This can be called in any thread. If "final" will not turn on any
- * read/write ready stuff.
+ * Note that CMD_WAITING requires no further action from the caller, the
+ * background pselect process will complete the output and may signal the
+ * result via uty_cmd_signal().
*/
extern cmd_return_code_t
uty_term_out_push(vio_vf vf, bool final)
@@ -258,8 +269,17 @@ uty_term_out_push(vio_vf vf, bool final)
vty_cli cli = vf->cli ;
utw_ret_t done ;
- /* If have something in the obuf that needs to be written, then if not already
- * out_active, make sure the command line is clear, and set out_active.
+ qassert(vf->vout_state == vf_open) ;
+ qassert(!vf->blocking) ;
+
+ /* If squelching, dump anything we have in the obuf.
+ */
+ if (vf->vio->cancel)
+ vio_fifo_clear(vf->obuf, false) ; /* keep end mark */
+
+ /* If have something in the obuf that needs to be written, then if not
+ * already out_active, make sure the command line is clear, and set
+ * out_active.
*/
if (!cli->out_active && !vio_fifo_empty(vf->obuf))
{
@@ -271,34 +291,39 @@ uty_term_out_push(vio_vf vf, bool final)
/* Give the terminal writing a shove.
*
* If final, keep pushing while succeeds in writing without blocking.
+ *
+ * Note that is only called "final" when closing the vout, by which time
+ * the "--more--" handling has been turned off and any output has been
+ * released.
*/
- if (final)
- cli->flush = cli->out_active ; /* make sure empty everything */
-
- do
- {
- if (final)
- vio_lc_counter_reset(cli->olc) ;
-
- done = uty_term_write(vf) ;
- }
- while (final && (done == utw_paused)) ;
-
if (!final)
+ done = uty_term_write(vf) ;
+ else
{
- if (done == utw_error)
- return CMD_IO_ERROR ; /* TODO */
-
- if ((done & utw_blocked) != 0)
+ do
{
- confirm((utw_paused & utw_blocked) != 0) ;
-
- uty_term_set_readiness(vf, write_ready) ;
- return CMD_WAITING ;
- } ;
+ vio_lc_counter_reset(cli->olc) ;
+ done = uty_term_write(vf) ;
+ } while (done == utw_paused) ;
} ;
- return CMD_SUCCESS ;
+ /* Deal with the result
+ *
+ * If required and if not final make sure that write ready is set, so
+ * that the pselect() process can pursue the issue.
+ *
+ * Return code depends on utw_xxx
+ */
+ if (done == utw_done)
+ return CMD_SUCCESS ; /* don't set write ready */
+
+ if (done == utw_error)
+ return CMD_IO_ERROR ; /* don't set write ready */
+
+ if (!final)
+ uty_term_set_readiness(vf, write_ready) ;
+
+ return CMD_WAITING ; /* waiting for write ready */
} ;
/*------------------------------------------------------------------------------
@@ -319,14 +344,14 @@ uty_term_read_close(vio_vf vf, bool final)
{
vty_io vio ;
+ qassert(vf->vin_state == vf_end) ;
+
/* Get the vio and ensure that we are all straight */
vio = vf->vio ;
- assert((vio->vin == vio->vin_base) && (vio->vin == vf)) ;
- assert(vio->vin->vin_state == vf_closing) ;
+ qassert((vio->vin == vio->vin_base) && (vio->vin == vf)) ;
- /*
- */
- uty_set_monitor(vio, 0) ;
+ /* Kill monitor state */
+ uty_set_monitor(vio, off) ;
/* Close the CLI as far as possible, leaving output side intact.
*
@@ -335,11 +360,6 @@ uty_term_read_close(vio_vf vf, bool final)
*/
uty_cli_close(vf->cli, false) ;
- /* Log closing of VTY_TERMINAL
- */
- assert(vio->vty->type == VTY_TERMINAL) ;
- zlog (NULL, LOG_INFO, "Vty connection (fd %d) close", vio_vfd_fd(vf->vfd)) ;
-
return CMD_SUCCESS ;
} ;
@@ -355,7 +375,8 @@ extern void
uty_term_close_reason(vio_vf vf, const char* reason)
{
vio_lc_clear(vf->cli->olc) ;
- vio_fifo_clear(vf->cli->cbuf, true) ;
+
+ vf->cli->mon_active = false ; /* stamp on any monitor output */
uty_cli_out(vf->cli, "%% %s%s", reason, uty_cli_newline) ;
} ;
@@ -364,56 +385,77 @@ uty_term_close_reason(vio_vf vf, const char* reason)
* Close the writing side of VTY_TERMINAL.
*
* Assumes that the read side has been closed already, and so this is the last
- * thing to be closed.
+ * thing to be closed. Any monitor state was turned off earlier when the read
+ * side was closed.
*
* Kicks the output side:
*
- * if final, will push as much as possible until would block.
+ * if final, will push as much as possible until all gone, would block or
+ * gets error. In any event, closes the cli, final.
*
* if not final, will push another tranche and let the uty_term_ready() keep
* pushing until buffers empty and can uty_cmd_signal().
*
- * Returns: CMD_SUCCESS => all written (or final) and CLI closed.
- * CMD_WAITING => write ready running to empty the buffers
- * CMD_IO_ERROR =>
- * others TODO
+ * Returns: CMD_SUCCESS => all written,
+ * or cannot write anything (more),
+ * or final and wrote what could
+ * CMD_WAITING -- not "final" => waiting for output to complete
+ * "final" => would have waited but did not.
+ *
+ * NB: if an error occurs while writing, that will have been logged, but there
+ * is nothing more to be done about it here -- so does not return
+ * CMD_IO_ERROR.
*/
extern cmd_return_code_t
-uty_term_write_close(vio_vf vf, bool final, bool base)
+uty_term_write_close(vio_vf vf, bool final)
{
cmd_return_code_t ret ;
vty_io vio ;
+ VTY_ASSERT_LOCKED() ;
+
/* Get the vio and ensure that we are all straight
*
* Can only be the vout_base and must also be the vin_base, and the vin_base
* must now be closed.
*/
vio = vf->vio ;
- assert((vio->vout == vio->vout_base) && (vio->vout == vf)) ;
- assert((vio->vin == vio->vin_base) && (vio->vin->vin_state == vf_closed)) ;
+ qassert((vio->vout == vio->vout_base) && (vio->vout == vf)) ;
+ qassert((vio->vin == vio->vin_base) && (vio->vin->vin_state == vf_closed)) ;
+
+ ret = CMD_SUCCESS ;
+
+ if (vf->vout_state == vf_open)
+ {
+ ret = uty_term_out_push(vf, final) ;
- ret = uty_term_out_push(vf, final) ;
+ if (ret != CMD_WAITING)
+ ret = CMD_SUCCESS ;
+ } ;
if (final)
- vf->cli = uty_cli_close(vf->cli, final) ;
+ {
+ vf->cli = uty_cli_close(vf->cli, final) ;
+
+ qassert(vio->vty->type == VTY_TERMINAL) ;
+ zlog (NULL, LOG_INFO, "Vty connection (fd %d) close",
+ vio_vfd_fd(vf->vfd)) ;
+ } ;
return ret ;
} ;
/*==============================================================================
- * Action routines for VIN_TERM/VOUT_TERM type vin/vout objects
- */
-
-/*==============================================================================
* Readiness and the VIN_TERM type vin.
*
* For TERM stuff the driving force is write ready. This is used to prompt the
* VOUT_TERM when there is outstanding output (obviously), but also if there
* is buffered input in the keystroke stream.
*
- * The VIN_TERM uses read ready only when it doesn't set write ready. Does
- * not set both at once.
+ * The VIN_TERM is read ready permanently, until eof is met. Note that the
+ * read timeout is reset each time uty_term_set_readiness is called. When
+ * eof is met, the VIN_TERM is read closed, which prevents any further setting
+ * of read ready and its timeout.
*/
static void uty_term_ready(vio_vf vf) ;
@@ -421,17 +463,17 @@ static void uty_term_ready(vio_vf vf) ;
/*------------------------------------------------------------------------------
* Set read/write readiness -- for VIN_TERM/VOUT_TERM
*
- * Note that sets only one of read or write, and sets write for preference.
+ * Is permanently read-ready (until eof or no longer vin_state == vf_open).
*/
extern void
uty_term_set_readiness(vio_vf vf, vty_readiness_t ready)
{
VTY_ASSERT_LOCKED() ;
- if ((ready & write_ready) != 0)
+ if ((ready & write_ready) != 0)
uty_vf_set_write(vf, on) ;
- else if ((ready & read_ready) != 0)
- uty_vf_set_read(vf, on) ;
+
+ uty_vf_set_read(vf, on) ;
} ;
/*------------------------------------------------------------------------------
@@ -442,9 +484,11 @@ uty_term_read_ready(vio_vfd vfd, void* action_info)
{
vio_vf vf = action_info ;
- assert(vfd == vf->vfd) ;
+ qassert(vfd == vf->vfd) ;
vf->cli->paused = false ; /* read ready clears paused */
+
+ uty_term_read(vf) ;
uty_term_ready(vf) ;
} ;
@@ -456,7 +500,7 @@ uty_term_write_ready(vio_vfd vfd, void* action_info)
{
vio_vf vf = action_info ;
- assert(vfd == vf->vfd) ;
+ qassert(vfd == vf->vfd) ;
uty_term_ready(vf) ;
} ;
@@ -501,25 +545,25 @@ static void
uty_term_ready(vio_vf vf)
{
vty_readiness_t ready ;
- utw_ret_t done ;
- bool signal ;
+ utw_ret_t done, done_before ;
VTY_ASSERT_LOCKED() ;
- /* Start by trying to write away any outstanding stuff, and then another
- * tranche of any outstanding output.
+ /* Will attempt to write away any pending stuff, then for each call of
+ * uty_term_ready, put out another tranche of output (unless in '--more--'
+ * state).
*/
- ready = not_ready ;
-
if (!vf->cli->more_enabled)
vio_lc_counter_reset(vf->cli->olc) ; /* do one tranche */
- done = uty_term_write(vf) ;
- signal = ((done == utw_done) || (done == utw_stopped)) ;
-
- while (done != utw_error)
+ /* Now loop kicking the CLI and the output, until stops changing.
+ *
+ * This is because the CLI may generate more to write, and writing stuff
+ * away may release the CLI.
+ */
+ done = utw_null ;
+ do
{
- utw_ret_t done_before ;
done_before = done ;
/* Kick the CLI, which may advance either because there is more input,
@@ -532,59 +576,45 @@ uty_term_ready(vio_vf vf)
/* Now try to write away any new output which may have been generated
* by the CLI.
+ *
+ * Note that when enters "--more--" will return utw_more_enter, once,
+ * which causes a loop back to uty_cli(), which will start the process.
+ * When comes through here a second time, will return utw_done, once
+ * any prompt etc has been output.
*/
done = uty_term_write(vf) ;
- if (done == done_before)
- break ; /* quit if no change in response */
-
- if ((done == utw_done) || (done == utw_stopped))
- signal = true ;
- } ;
-
- if (done == utw_error)
- ; /* TODO !! */
+ if (done == utw_error)
+ return ; /* quit if in error */
- if ((done & utw_blocked) != 0)
- {
- confirm((utw_paused & utw_blocked) != 0) ;
- ready |= write_ready ;
- } ;
+ } while (done != done_before) ;
- if ((done != utw_blocked) && (done != utw_error))
- {
- /* Since is not output blocked, tell master that is now ready. */
- if (vf->pr_master != NULL)
- uty_pipe_return_slave_ready(vf) ;
- } ;
+ if (done != utw_done) /* isn't utw_error, either */
+ ready |= write_ready ;
uty_term_set_readiness(vf, ready) ;
- /* Signal the command loop if out_active and the buffers empty out.
+ /* Signal the command loop if not waiting for write any more.
*/
- if (signal)
+ if ((ready & write_ready) == 0)
uty_cmd_signal(vf->vio, CMD_SUCCESS) ;
} ;
/*------------------------------------------------------------------------------
* Read timer has expired.
*
- * If closing, then this is curtains -- have waited long enough !
- *
- * TODO .... sort out the VTY_TERMINAL time-out & death-watch timeout
- *
- * Otherwise, half close the VTY and leave it to the death-watch to sweep up.
+ * Discard anything in the keystroke stream and set it "eof, timed-out". This
+ * will be picked up by the CLI and a cmd_do_timed-out will float out.
*/
static vty_timer_time
uty_term_read_timeout(vio_timer timer, void* action_info)
{
vio_vf vf = action_info ;
- assert(timer == vf->vfd->read_timer) ;
+ qassert(timer == vf->vfd->read_timer) ;
VTY_ASSERT_LOCKED() ;
- vf->vin_state = vf_timed_out ;
keystroke_stream_set_eof(vf->cli->key_stream, true) ; /* timed out */
vf->cli->paused = false ;
@@ -597,24 +627,20 @@ uty_term_read_timeout(vio_timer timer, void* action_info)
/*------------------------------------------------------------------------------
* Write timer has expired.
*
- * If closing, then this is curtains -- have waited long enough !
- *
- * TODO .... sort out the VTY_TERMINAL time-out & death-watch timeout
- *
- * Otherwise, half close the VTY and leave it to the death-watch to sweep up.
+ * Signal write timeout error.
*/
static vty_timer_time
uty_term_write_timeout(vio_timer timer, void* action_info)
{
vio_vf vf = action_info ;
- assert(timer == vf->vfd->read_timer) ;
+ qassert(timer == vf->vfd->write_timer) ;
VTY_ASSERT_LOCKED() ;
vf->cli->paused = false ;
-//uty_close(vio, true, qs_set(NULL, "Timed out")) ; TODO
+ uty_vf_error(vf, verr_to_vout, 0) ;
return 0 ;
} ;
@@ -650,38 +676,69 @@ vty_term_pause_timeout(qtimer qtr, void* timer_info, qtime_mono_t when)
/*------------------------------------------------------------------------------
* Read a lump of bytes and shovel into the keystroke stream
*
- * This function is called from the vty_cli to top up the keystroke buffer,
- * or in the stealing of a keystroke to end "--more--" state.
- *
* NB: need not be in the term_ready path. Indeed, when the VTY_TERMINAL is
* initialised, this is called to suck up any telnet preamble.
*
- * Steal keystroke if required -- see keystroke_input()
+ * NB: the terminal is permanently read-ready, so will keep calling this
+ * until all input is hoovered up. For real terminals it is assumed that
+ * reading a lump of bytes this small will immediately empty the input
+ * buffer.
+ *
+ * When reaches EOF on the input eof is set in the keystroke stream, and the
+ * vfd is read closed. Read closing the vfd turns off any timeout and prevents
+ * any further setting of read_ready (to avoid permanent read_ready !). Does
+ * NOT set vf->vin_state to vf_end, because that is not true until the
+ * keystroke stream is empty. Once eof is set in the keystroke stream, this
+ * code will not attempt any further input from the vfd.
*
* Returns: 0 => nothing available
* > 0 => read at least one byte
- * -1 => EOF (or not open, or failed, or timed out, ...)
+ * == -1 => I/O error
+ * == -2 => hit EOF (without reading anything else)
*/
extern int
-uty_term_read(vio_vf vf, keystroke steal)
+uty_term_read(vio_vf vf)
{
+ keystroke_stream stream ;
unsigned char buf[500] ;
int get ;
+ stream = vf->cli->key_stream ;
+
+ if (keystroke_stream_met_eof(stream))
+ return -2 ; /* already seen EOF */
+
if (vf->vin_state != vf_open)
- return -1 ; /* at EOF if not open */
+ {
+ /* If is not vf_open, but also not seen EOF on the keystroke stream,
+ * then now is a good moment to empty out the keystroke stream and
+ * force it to EOF.
+ */
+ keystroke_stream_set_eof(vf->cli->key_stream, false) ;
+ return -2 ;
+ } ;
+ /* OK: read from input and pass result to keystroke stream.
+ */
get = read_nb(vio_vfd_fd(vf->vfd), buf, sizeof(buf)) ;
- if (get >= 0)
- keystroke_input(vf->cli->key_stream, buf, get, steal) ;
- else if (get < 0)
+ /* -1 <=> error, -2 <=> EOF */
+ if (get != 0)
{
if (get == -1)
- uty_vf_error(vf, "read", errno) ;
+ {
+ /* Error: signal to command loop and force key_stream empty */
+ uty_vf_error(vf, verr_io_vin, errno) ;
+ keystroke_stream_set_eof(vf->cli->key_stream, false) ;
+ /* not timed-out */
+ }
+ else
+ {
+ /* Not error. get < 0 => EOF and that is set in key_stream. */
+ keystroke_input(vf->cli->key_stream, buf, get) ;
+ } ;
- keystroke_input(vf->cli->key_stream, NULL, 0, steal) ;
- /* Tell keystroke stream that EOF met */
- get = -1 ;
+ if (get < 0)
+ vio_vfd_read_close(vf->vfd) ;
} ;
return get ;
@@ -719,59 +776,40 @@ uty_term_mon_write(vio_vf vf)
uty_cli_pre_monitor(vf->cli) ; /* make sure in a fit state */
- done = uty_term_write(vf) ; /* TODO -- errors !! */
-
- if ((done & utw_blocked) != 0)
- {
- confirm((utw_paused & utw_blocked) != 0) ;
-
- uty_term_set_readiness(vf, write_ready) ;
- } ;
+ done = uty_term_write(vf) ; /* this calls uty_vf_error() if
+ * there are any errors */
+ if ((done != utw_done) && (done != utw_error))
+ uty_term_set_readiness(vf, write_ready) ;
} ;
/*------------------------------------------------------------------------------
* Write as much as possible of what there is.
*
- * Move to more_wait if required. TODO
+ * Move to more_wait if required.
*
* If is cli->flush, then when all buffers are emptied out, clears itself and
* the out_active flag.
*
* Returns:
*
- * utw_error -- I/O error -- see errno (utw_error = -1)
- *
- * utw_blocked -- write blocked -- some write operation would block
+ * utw_error -- I/O error either now or sometime earlier.
*
- * utw_paused -- have written as much as line control allows in one go.
+ * utw_done -- have written everything can find
*
- * NB: this does NOT mean is now in more_wait, it means that
- * to write more it is necessary to clear the line
- * control pause state.
+ * utw_blocked -- write blocked -- some write operation would block
*
- * utw_stopped -- have done as much as can do -- no more output is possible
- * until some external event changes things.
+ * Need to set write ready & wait for it.
*
- * This implies that any pending output has completed, in
- * particular the line control iovec and the cli->cbuf are
- * both empty.
+ * utw_paused -- have written as much as line control allows in one go.
*
- * This state includes:
+ * Note that is *not* in "--more--" state, this is all to
+ * do with limiting work on each visit.
*
- * * !out_active -- if there is something in the vf->obuf,
- * we are not yet ready to output it.
+ * Need to set write ready & wait for it.
*
- * * more_wait -- waiting for user
+ * utw_more_enter -- has just entered "--more--" state
*
- * utw_done -- have written everything can find, unless more output
- * arrives, there is no more to do.
- *
- * If was cli->flush the all output really has gone, as
- * well as any incomplete line. Also the out_active and
- * the flush flags will have been cleared.
- *
- * If was not cli->flush, the out_active state persists,
- * and there may be an incomplete line still pending.
+ * Need either to set write ready, or call the CLI.
*/
static utw_ret_t
uty_term_write(vio_vf vf)
@@ -783,33 +821,44 @@ uty_term_write(vio_vf vf)
VTY_ASSERT_LOCKED() ;
- /* If the vout is neither vf_open, not vf_closing, discard all buffered
+ /* If the vout is neither vf_open nor vf_closing, discard all buffered
* output, and return all done.
*/
- if ((vf->vout_state != vf_open) && (vf->vout_state != vf_closing))
+ if (vf->vout_state != vf_open)
{
+ qassert(vf->vout_state == vf_end) ;
+
vio_fifo_clear(vf->obuf, false) ;
vio_fifo_clear(cli->cbuf, false) ;
vio_lc_clear(cli->olc) ;
cli->out_active = false ;
- cli->flush = false ;
cli->more_wait = false ;
cli->more_enter = false ;
- return utw_done ;
+ return utw_error ;
} ;
/* Any outstanding line control output takes precedence */
- ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ;
- if (ret != utw_done)
- return ret ; /* utw_blocked or utw_error */
+ if (vio_lc_pending(cli->olc))
+ {
+ ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ;
+ if (ret != utw_done)
+ return ret ; /* utw_blocked or utw_error */
+ } ;
/* Next: empty out the cli output */
did = vio_fifo_write_nb(cli->cbuf, vio_vfd_fd(vf->vfd), true) ;
- if (did != 0)
- return (did < 0) ? utw_error : utw_blocked ;
+
+ if (did > 0)
+ return utw_blocked ;
+
+ if (did < 0)
+ {
+ uty_vf_error(vf, verr_io_vout, errno) ;
+ return utw_error ;
+ } ;
/* Next: if there is monitor output to deal with, deal with it.
*
@@ -827,20 +876,23 @@ uty_term_write(vio_vf vf)
LOG_UNLOCK() ;
- if (did != 0)
- return (did < 0) ? utw_error : utw_blocked ;
+ if (did > 0)
+ return utw_blocked ;
+
+ if (did < 0)
+ {
+ uty_vf_error(vf, verr_io_vout, errno) ;
+ return utw_error ;
+ } ;
uty_cli_post_monitor(vf->cli) ;
} ;
- /* If not out_active, or in more_wait, then we are stopped, waiting for some
+ /* If not out_active, or in more_wait, then we are done, waiting for some
* external event to move things on.
*/
- if (cli->flush)
- assert(cli->out_active) ; /* makes no sense, otherwise */
-
- if (!cli->out_active || cli->more_wait)
- return utw_stopped ;
+ if ((!cli->out_active) || (cli->more_wait))
+ return utw_done ; /* can do no more */
/* Push the output fifo and any complete line fragments that may be buffered
* in hand in the line control -- this will stop if the line counter becomes
@@ -870,7 +922,7 @@ uty_term_write(vio_vf vf)
break ;
} ;
- if ((have == 0) && (cli->flush))
+ if ((have == 0) && !cli->in_progress)
vio_lc_flush(cli->olc) ;
ret = uty_term_write_lc(cli->olc, vf, vf->obuf) ;
@@ -890,12 +942,12 @@ uty_term_write(vio_vf vf)
*/
if ((have != 0) || vio_lc_have_complete_line_in_hand(cli->olc))
{
- assert(vio_lc_counter_is_exhausted(cli->olc)) ;
+ qassert(vio_lc_counter_is_exhausted(cli->olc)) ;
if (cli->more_enabled)
{
uty_cli_enter_more_wait(cli) ;
- return utw_stopped ;
+ return utw_more_enter ;
}
else
return utw_paused ; /* artificial block */
@@ -910,22 +962,21 @@ uty_term_write(vio_vf vf)
* ...if not cli->flush, we are stopped, waiting for something else to
* happen.
*/
- assert(!cli->more_wait && !cli->more_enter) ;
+ qassert(!cli->more_wait && !cli->more_enter) ;
- if (!cli->flush)
- return utw_stopped ;
+ if (cli->in_progress)
+ return utw_done ; /* can do no more */
- /* Even more exciting: is cli->flush !
+ /* Even more exciting: is !cli->in_progress !
*
* This means that any incomplete line must have been flushed, above.
* So all buffers MUST be empty.
*/
- assert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ;
+ qassert(vio_fifo_empty(vf->obuf) && vio_lc_is_empty(cli->olc)) ;
cli->out_active = false ;
- cli->flush = false ;
- return utw_done ;
+ return utw_done ; /* absolutely all done */
} ;
/*------------------------------------------------------------------------------
@@ -937,7 +988,7 @@ uty_term_write(vio_vf vf)
*
* Returns: utw_blocked => blocked
* utw_done => all gone (may still have stuff "in hand")
- * utw_error => failed
+ * utw_error => failed -- error posted to uty_vf_error()
*/
static utw_ret_t
uty_term_write_lc(vio_line_control lc, vio_vf vf, vio_fifo vff)
@@ -946,7 +997,9 @@ uty_term_write_lc(vio_line_control lc, vio_vf vf, vio_fifo vff)
did = vio_lc_write_nb(vio_vfd_fd(vf->vfd), lc) ;
- if (did > 0)
+ if (did < 0)
+ uty_vf_error(vf, verr_io_vout, errno) ;
+ else if (did > 0)
return utw_blocked ;
vio_fifo_clear_hold_mark(vff) ; /* finished with FIFO contents */
@@ -1032,7 +1085,7 @@ uty_term_listen_addrinfo(const char *addr, unsigned short port)
if ((ainfo->ai_family != AF_INET) && (ainfo->ai_family != AF_INET6))
continue;
- assert(ainfo->ai_family == ainfo->ai_addr->sa_family) ;
+ qassert(ainfo->ai_family == ainfo->ai_addr->sa_family) ;
ret = uty_term_listen_open(ainfo->ai_family, ainfo->ai_socktype,
ainfo->ai_protocol, ainfo->ai_addr, port) ;
@@ -1498,8 +1551,8 @@ uty_telnet_command(vio_vf vf, keystroke stroke, bool callback)
p = stroke->buf ;
left = stroke->len ;
- passert(left >= 1) ; /* must be if not broken ! */
- passert(stroke->value == *p) ; /* or something is wrong */
+ qassert(left >= 1) ; /* must be if not broken ! */
+ qassert(stroke->value == *p) ; /* or something is wrong */
++p ; /* step past X of IAC X */
--left ;
@@ -1508,7 +1561,7 @@ uty_telnet_command(vio_vf vf, keystroke stroke, bool callback)
switch (stroke->value)
{
case tn_SB:
- passert(left > 0) ; /* or parser failed */
+ qassert(left > 0) ; /* or parser failed */
o = *p++ ; /* the option byte */
--left ;