diff options
Diffstat (limited to 'lib/vty_io.h')
-rw-r--r-- | lib/vty_io.h | 485 |
1 files changed, 262 insertions, 223 deletions
diff --git a/lib/vty_io.h b/lib/vty_io.h index ecd7a451..5db12ca2 100644 --- a/lib/vty_io.h +++ b/lib/vty_io.h @@ -25,145 +25,251 @@ #ifndef _ZEBRA_VTY_IO_H #define _ZEBRA_VTY_IO_H -#include "zebra.h" +//#include "zebra.h" #include "misc.h" +//#include <errno.h> -#include <errno.h> - +#include "vty_local.h" +#include "command_local.h" #include "vty_io_basic.h" -#include "uty.h" -#include "vty.h" #include "vio_fifo.h" -#include "vio_lines.h" -#include "keystroke.h" #include "thread.h" -#include "command.h" +#include "command_execute.h" #include "qstring.h" /*============================================================================== - * Here are structures and other definitions which are shared by: - * - * vty.c -- the main vty handler - * vty_cli.c -- which handles the command line stuff - * vty_io.c -- .... - * - * The "struct vty" is used extensively across the Quagga daemons, where it - * has two functions relating to command handling as: - * - * 1) a "file handle" for output produced by commands - * - * 2) the holder of some context -- notably the current command "node" -- for - * command execution to use + * Structures and other definitions for the top level VTY I/O. * - * The bulk of "struct vty" is, therefore, private to vty.c and is factored - * out into the "struct vty_io". - * - * To reduce the size of vty.c, some groups of functions are separated into: - * - * vty_cli.c -- which looks after the keystroke by keystroke handling - * of the command line. + * There is one struct vty_io per VTY, which contains, inter alia, the vin + * and vout stacks. * + * The vin and vout stacks contain one or more struct vty_vf -- one per + * input and/or output associated with the VTY. */ -/*============================================================================== - * VTY CLI and OUT types +enum +{ + VTY_WATCH_DOG_INTERVAL = 5, /* interval between barks */ + + VTY_HALF_CLOSE_TIMEOUT = 120, /* timeout after half_close */ + + VTY_TIMEOUT_DEFAULT = 600, /* terminal timeout value */ +} ; + +/*------------------------------------------------------------------------------ + * VTY VIN and OUT types */ enum vio_in_type /* Command input */ { - VIN_NONE = 0, /* no input at all */ + VIN_NONE = 0, /* not a valid input type */ VIN_TERM, /* telnet terminal */ - VIN_SHELL, /* vty_shell input */ + VIN_VTYSH, /* vty_shell input */ VIN_FILE, /* ordinary file input */ VIN_PIPE, /* pipe (from child process) */ - VIN_CONFIG, /* config file ?? */ + VIN_CONFIG, /* config file */ + + VIN_PIPE_RETURN, /* */ + + /* The VIN types >= VIN_SPECIALS do not have an associated fd. + * + * These can coexist with a VOUT which does have an associated fd. + */ + VIN_SPECIALS, /* all special from now on */ + + VIN_DEV_NULL = VIN_SPECIALS, + /* black hole input */ } ; typedef enum vio_in_type vio_in_type_t ; enum vio_out_type /* Command output */ { - VOUT_NONE = 0, /* no output at all */ + VOUT_NONE = 0, /* not a valid output type */ VOUT_TERM, /* a telnet terminal */ - VOUT_SHELL, /* a vty_shell output pipe */ + VOUT_VTYSH, /* a vty_shell output pipe */ VOUT_FILE, /* ordinary file */ VOUT_PIPE, /* pipe (to child process) */ + VOUT_CONFIG, /* config file ?? */ + + /* The VOUT types >= VOUT_SPECIALS do not have an associated fd. + * + * These can coexist with a VIN which does have an associated fd. + */ + VOUT_SPECIALS, /* all special from now on */ + + VOUT_DEV_NULL = VOUT_SPECIALS, + /* black hole output */ + VOUT_STDOUT, /* stdout */ VOUT_STDERR, /* stderr */ }; typedef enum vio_out_type vio_out_type_t ; /*------------------------------------------------------------------------------ - * VIO file structure + * State of a vf or of the entire vio. + * + * For a vf: I/O is possible iff vf_open -- has separate state for vin/vout. + * + * For a vio: used to manage the closing process. + */ +enum vf_state +{ + vf_closed = 0, /* not active -- may be discarded */ + + vf_open = 1, /* open for business */ + + vf_eof = 2, /* open, but at eof */ + vf_error = 3, /* open, but error reported */ + + vf_closing = 4, /* open, but in process of closing */ +} ; +typedef enum vf_state vf_state_t ; + +/*------------------------------------------------------------------------------ + * vty_vf -- "vty file" structure * - * All I/O is non-blocking for all sources and sinks of VIO stuff. + * A vio_vf may be a read, write or read/write object. + * + * All I/O is via vio_vfd objects, except for VOUT_STDOUT and VOUT_STDERR. + * The vio_vfd layer hides the differences between the qpthreads an legacy + * thread environments. + * + * The VOUT_STDOUT and VOUT_STDERR are handled as direct output to the standard + * i/o file handles. In the case of a VTY_CONFIG_READ, the vin is VIN_CONFIG + * and the vout is VOUT_STDOUT, and these can share a single vty_vf. * * Also used for the associated listeners. */ +struct vty_io ; /* Forward reference */ +typedef struct vty_io* vty_io ; + typedef struct vio_vf* vio_vf ; struct vio_vf { - vty_io vio ; /* parent */ + vty_io vio ; /* parent */ + + char* name ; /* MTYPE_VTY_NAME (if any) */ + + /* Input side. */ + + vio_in_type_t vin_type ; + vf_state_t vin_state ; + vio_vf vin_next ; /* list of inputs */ + + + struct vty_cli* cli ; /* NULL if not a VTY_TERMINAL ! */ + + vio_fifo ibuf ; /* input fifo (if required) */ - vio_in_type_t vin_type ; - vio_vf vin_next ; /* list of inputs */ + qstring_t cl ; /* command line buffer */ + bool line_complete ; /* false => line in construction */ + uint line_number ; /* number of first line in cl */ + uint line_step ; /* number of real lines in cl */ - vio_out_type_t vout_type ; - vio_vf vout_next ; /* list of outputs */ + cmd_parse_type_t parse_type ; /* iff vin_type != VIN_NONE */ + bool reflect_enabled ; /* false if vin_type == VIN_NONE */ - vio_fifo obuf ; /* pointer to fifo */ - vio_line_control olc ; /* pointer to lc */ + /* Output side. */ - vio_fd vfd ; + vio_out_type_t vout_type ; + vf_state_t vout_state ; + vio_vf vout_next ; /* list of outputs */ - bool blocking ; /* using blocking reads */ - bool closing ; /* suppress read/write ready */ + vio_fifo obuf ; /* output fifo (if required) */ - bool read_open ; /* reads returns 0 if not */ - bool write_open ; /* writes complete instantly if not */ - int error_seen ; /* non-zero => failed */ + bool out_enabled ; /* false if vout_type == VOUT_NONE */ - on_off_b read_on ; - on_off_b write_on ; + /* I/O */ + + vio_vfd vfd ; /* vty_io_basic "file descriptor" */ + + bool blocking ; /* using blocking I/O (config read) */ + + int error_seen ; /* non-zero => failed */ + + on_off_b read_on ; + on_off_b write_on ; vty_timer_time read_timeout ; vty_timer_time write_timeout ; + } ; -enum vty_readiness /* bit significant */ +enum vty_readiness /* bit significant */ { not_ready = 0, - read_ready = 1, - write_ready = 2, /* takes precedence */ - now_ready = 4 + read_ready = BIT(0), + write_ready = BIT(1), /* may take precedence */ + now_ready = BIT(2) } ; +typedef enum vty_readiness vty_readiness_t ; /*------------------------------------------------------------------------------ * The vty_io structure * + * The main elements of the vty_io object are the vin and vout stacks. + * + * One of the challenges is managing the closing of VTY objects. First, + * cannot close and free a VTY object which is in the hands of a command + * function, or which is queued to or from a command function. Second, + * do not wish to completely close an output until have given it a chance + * to clear any buffered output. + * + * * + * "cmd_running" means that the VTY is in hands of (or has been passed to) + * a command loop -- the VTY cannot be fully closed until that is no + * longer the case. * + * "blocking" is set for configuration reading VTY, so that everything is + * done with blocking I/O. * + * "closing" means that the vty has been closed (!), but a command + * and or output may still be active: * + * - if is a socket, will have shut_down the read side (half-closed) + * + * - any further attempts to read will give "eof" + * + * - there may be a command in execution -- see "cmd_running". + * + * - further writing will be honoured. + * + * - the write side may still be active, attempting to empty out any + * pending output. + * + * "closed" means the vty has been fully and finally closed. + * + * - any further attempts to write will be ignored, but return instant + * success. + * + * - the file/socket has been fully closed. + * + * - the VTY and all attached structures can be reaped by the death_watch. */ +struct vty_cli ; /* forward reference -- vty_cli.h is + *not* included, because that refers + back to the vty_io ! */ -struct vty_io +struct vty_io /* typedef appears above */ { - struct vty* vty ; /* the related vty */ - char *name ; /* for VTY_TERM is IP address) */ + vty vty ; /* the related vty */ - /* vin stack */ - vio_vf vin ; + vio_vf vin ; /* vin stack */ vio_vf vin_base ; + uint vin_depth ; - /* vout stack */ - vio_vf vout ; + vio_vf vout ; /* vout stack */ vio_vf vout_base ; + uint vout_depth ; + + vio_vf vout_closing ; /* vout closing list */ /* List of all vty_io objects */ struct dl_list_pair(vty_io) vio_list ; @@ -171,193 +277,102 @@ struct vty_io /* List of all vty_io that are in monitor state */ struct dl_list_pair(vty_io) mon_list ; - /* VTY state */ - - bool half_closed ; /* => on death watch list until closed */ - bool closed ; /* => all I/O terminated - will also be half_closed */ - - char* close_reason ; /* message to be sent, once all other - output has completed, giving reason - for closing the VTY. */ - - - - - - /* When writing configuration file */ - enum vty_type real_type ; - - int file_fd ; - int file_error ; - - /* Failure count for login attempts */ - int fail; - - /* History of commands */ - vector_t hist ; - int hp ; /* History lookup current point */ - int hindex; /* History insert end point */ - - /* Window width/height as reported by Telnet. 0 => unknown */ - int width; - int height; - - /* Configure lines. */ - int lines; - bool lines_set ; /* true <=> explicitly set */ - - /* Terminal monitor. */ - bool monitor ; - bool monitor_busy ; - - /* Terminal timeout in seconds -- 0 => none */ - vty_timer_time v_timeout ; - - /*------------------------------------------------------------------------- - * CLI_TERM stuff. - */ - - keystroke_stream key_stream ; - - /* cli_drawn <=> the current prompt and user input occupy the current - * line on the screen. + /* VTY state * - * cli_dirty <=> the last command output did not end with a newline. + * "blocking" is set for configuration reading VTY, so that everything is + * done with blocking I/O. * - * If cli_drawn is true, the following are valid: + * "half_closed" means that the vty has been closed (!), but a command + * and or output may still be active: * - * cli_prompt_len -- the length of the prompt part. - * (will be the "--more--" prompt in cli_more_wait) + * - if is a socket, will have shut_down the read side (half-closed) * - * cli_extra_len -- the length of any ^X at the cursor position - * (for when blocked waiting for queued command) + * - any further attempts to read will give "eof" * - * cli_echo_suppress -- the user part of the command line is suppressed + * - there may be a command in execution -- see "cmd_running". * - * NB: cli_echo_suppress is only used for password entry. - */ - bool cli_drawn ; - bool cli_dirty ; - - int cli_prompt_len ; - int cli_extra_len ; - - bool cli_echo_suppress ; - - /* "cache" for prompt -- when node or host name changes, prompt does */ - enum node_type cli_prompt_node ; - bool cli_prompt_set ; - qstring_t cli_prompt_for_node ; - - /* State of the CLI + * - further writing will be honoured. * - * cli_blocked -- blocked from processing keystrokes - * cmd_in_progress -- command dispatched (may be queued) - * cmd_out_enabled -- contents of the command FIFO may be written away - * cli_more_wait -- is in "--more--" wait state - */ - bool cli_blocked ; - bool cmd_in_progress ; - bool cmd_out_enabled ; - bool cli_more_wait ; - - /* This is used to control command output, so that each write_ready event - * generates at most one tranche of output. - */ - bool cmd_out_done ; - - /* This is set only if the "--more--" handling is enabled */ - bool cli_more_enabled ; - - /* Command Line(s) + * - the write side may still be active, attempting to empty out any + * pending output. + * + * "cmd_running" means that the VTY is in hands of (or has been passed to) + * a command loop -- the VTY cannot be fully closed until that is no + * longer the case. * - * cli_do -- when current command being prepared is completed (by - * CR/LF or otherwise) this says what there now is to be done. + * "closed" means the vty has been fully and finally closed. * - * cl -- current command line being prepared. + * - any further attempts to write will be ignored, but return instant + * success. * - * clx -- current command line being executed. + * - the file/socket has been fully closed. * - * NB: during command execution vty->buf is set to point at the '\0' - * terminated current command line being executed. + * - the VTY and all attached structures can be reaped by the death_watch. */ - enum cli_do cli_do ; + bool blocking ; /* => all I/O is blocking. */ - qstring_t cl ; - qstring_t clx ; + bool cmd_running ; /* => cannot be fully closed */ - /* CLI output buffering */ - vio_fifo_t cli_obuf ; + vf_state_t state ; -} ; + qstring close_reason ; /* message to be sent, once all other + output has completed, giving reason + for closing the VTY. */ -/*============================================================================== - * If possible, will use getaddrinfo() to find all the things to listen on. - */ -enum { -#if defined(HAVE_IPV6) && !defined(NRL) - VTY_USE_ADDRINFO = 1, -#else - VTY_USE_ADDRINFO = 0, -#endif + /* For ease of output, pointer to current vout->obuf */ + vio_fifo obuf ; /* NULL => no vout ! */ } ; /*============================================================================== * Functions */ -extern vty uty_new (vty_type_t type, int sock_fd) ; -extern void uty_close (vty_io vio, const char* reason) ; -extern void uty_close_final(vty_io vio, const char* reason) ; +extern int uty_out (vty_io vio, const char* format, ...) PRINTF_ATTRIBUTE(2, 3); +Inline int uty_vprintf(vty_io vio, const char *format, va_list args) ; + +Inline void uty_out_clear(vty_io vio) ; +Inline void uty_out_accept(vty_io vio) ; +Inline void uty_out_reject(vty_io vio) ; +extern vty uty_new (vty_type_t type) ; +extern bool uty_close(vty_io vio, bool final, qstring reason) ; -extern void uty_vin_add(vty_io vio, vio_vf vf, vio_in_type_t type, - vio_fd_action* read_action, vio_timer_action* read_timer_action) ; -extern void uty_vout_add(vty_io vio, vio_vf vf, vio_out_type_t type, - vio_fd_action* write_action, vio_timer_action* write_timer_action) ; +extern void uty_vin_close(vty_io vio) ; +extern void uty_vout_close(vty_io vio, bool final) ; +extern void uty_vin_close_stack(vty_io vio) ; +extern void uty_vout_close_stack(vty_io vio, bool final) ; +extern void uty_set_timeout(vty_io vio, vty_timer_time timeout) ; +extern void uty_vin_open(vty_io vio, vio_vf vf, vio_in_type_t type, + vio_vfd_action* read_action, + vio_timer_action* read_timer_action, + usize ibuf_size) ; +extern void uty_vout_open(vty_io vio, vio_vf vf, vio_out_type_t type, + vio_vfd_action* write_action, + vio_timer_action* write_timer_action, + usize obuf_size) ; -extern vio_vf uty_vf_new(vty_io vio, int fd, vfd_type_t type, +extern vio_vf uty_vf_new(vty_io vio, const char* name, int fd, vfd_type_t type, vfd_io_type_t io_type) ; -Inline int uty_vf_fd(vio_vf vf) ; -extern on_off_t uty_vf_set_read(vio_vf vf, on_off_t on) ; -extern on_off_t uty_vf_set_read_timeout(vio_vf vf, +extern on_off_b uty_vf_set_read(vio_vf vf, on_off_b on) ; +extern on_off_b uty_vf_set_read_timeout(vio_vf vf, vty_timer_time read_timeout) ; -extern on_off_t uty_vf_set_write(vio_vf vf, on_off_t on) ; -extern on_off_t uty_vf_set_write_timeout(vio_vf vf, +extern on_off_b uty_vf_set_write(vio_vf vf, on_off_b on) ; +extern on_off_b uty_vf_set_write_timeout(vio_vf vf, vty_timer_time write_timeout) ; - +extern int uty_vf_error(vio_vf vf, const char* what, int err) ; extern void uty_open_listeners(const char *addr, unsigned short port, const char *path) ; -extern void uty_add_listener(int fd, vio_fd_accept* accept) ; +extern void uty_add_listener(int fd, vio_vfd_accept* accept) ; extern void uty_close_listeners(void) ; extern void uty_watch_dog_init(void) ; extern void uty_watch_dog_start(void) ; extern void uty_watch_dog_stop(void) ; - - -extern int uty_output (struct vty *vty, const char *format, ...) - PRINTF_ATTRIBUTE(2, 3) ; -extern int uty_vprintf(struct vty *vty, const char *format, va_list args) ; -extern int uty_reflect(struct vty *vty) ; -extern void uty_out_clear(vty_io vio) ; -extern void uty_out_fflush(vty_io vio, FILE* file) ; - -extern void uty_set_height(vty_io vio) ; -extern void uty_cmd_output_start(vty_io vio) ; - -extern void uty_file_set_readiness(vio_vf vf, enum vty_readiness ready) ; -extern void uty_file_set_timer(vio_vf vf, unsigned long timeout) ; - -extern int uty_read (vty_io vio, keystroke steal) ; -extern int utysh_read (vty_io vio, qstring cl, qstring buf) ; - extern const char* uty_get_name(vty_io vio) ; extern void uty_set_monitor(vty_io vio, bool on) ; @@ -366,19 +381,6 @@ extern void uty_set_monitor(vty_io vio, bool on) ; * Inline Functions */ -/*------------------------------------------------------------------------------ - * Return the fd from a vio_fd structure - */ -Inline int -uty_vf_fd(vio_vf vf) -{ - return vio_fd_fd(vf->vfd) ; -} ; - -/*------------------------------------------------------------------------------ - * Return the fd from a vio_fd structure - */ - Inline bool uty_is_terminal(struct vty *vty) { @@ -397,4 +399,41 @@ uty_is_shell_client(struct vty *vty) return vty->type == VTY_SHELL_CLIENT ; } +/*------------------------------------------------------------------------------ + * Command output -- append to output buffer. + */ +Inline int +uty_vprintf(vty_io vio, const char *format, va_list args) +{ + return vio_fifo_vprintf(vio->obuf, format, args) ; +} ; + +/*------------------------------------------------------------------------------ + * Clear command output -- discard anything in the buffer, but keep markers. + */ +Inline void +uty_out_clear(vty_io vio) +{ + vio_fifo_clear(vio->obuf, false) ; +} ; + +/*------------------------------------------------------------------------------ + * Accept command output -- advance any end_mark to current put position. + */ +Inline void +uty_out_accept(vty_io vio) +{ + vio_fifo_step_end_mark(vio->obuf) ; +} ; + +/*------------------------------------------------------------------------------ + * Reject command output -- discard anything after the end_mark in the buffer, + * but keep markers. + */ +Inline void +uty_out_reject(vty_io vio) +{ + vio_fifo_back_to_end_mark(vio->obuf, true) ; +} ; + #endif /* _ZEBRA_VTY_IO_H */ |