diff options
Diffstat (limited to 'lib/vty.c')
-rw-r--r-- | lib/vty.c | 858 |
1 files changed, 690 insertions, 168 deletions
@@ -38,6 +38,36 @@ #include "network.h" #include <arpa/telnet.h> +#include "qpthreads.h" +#include "qpnexus.h" + +/* Needs to be qpthread safe */ +qpt_mutex_t* vty_mutex = NULL; +#ifdef NDEBUG +#define LOCK qpt_mutex_lock(vty_mutex); +#define UNLOCK qpt_mutex_unlock(vty_mutex); +#else +int vty_lock_count = 0; +int vty_lock_asserted = 0; +#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count; +#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex); +#define ASSERTLOCKED if(vty_lock_count==0 && !vty_lock_asserted){vty_lock_asserted=1;assert(0);} +#endif + +/* + * To make vty qpthread safe we use a single mutex. In general external + * routines have explicit locks, static routines assume that they are being + * called with the mutex already locked. There are a few exceptions, e.g. + * callbacks where static routines are being invoked from outside the module. + * + * As we are not using recursive mutexes so there are a few cases where + * both external and static versions of a routine exist. The former for use + * outside, the latter for use inside the module (and lock). In these cases + * the internal static versions starts uty_. + * + * vty and log recurse through each other, so the same mutex is used + * for both, i.e. they are treated as being part of the same monitor. + */ /* Vty events */ enum event @@ -53,7 +83,23 @@ enum event #endif /* VTYSH */ }; +/* Prototypes */ +static int uty_out (struct vty *vty, const char *format, ...); +static int uty_vout(struct vty *vty, const char *format, va_list args); static void vty_event (enum event, int, struct vty *); +static void uty_hello (struct vty *vty); +static void uty_close (struct vty *vty); +static int uty_config_unlock (struct vty *vty); +static int uty_shell (struct vty *vty); +static int uty_read (struct vty *vty, int vty_sock); +static int uty_flush (struct vty *vty, int vty_sock); +static void vty_event_t (enum event event, int sock, struct vty *vty); +static void vty_event_r (enum event event, int sock, struct vty *vty); +static int uty_accept (int accept_sock); +static int uty_timeout (struct vty *vty); +static void vty_timeout_r (qtimer qtr, void* timer_info, qtime_t when); +static void vty_read_r (qps_file qf, void* file_info); +static void vty_flush_r (qps_file qf, void* file_info); /* Extern host structure from command.c */ extern struct host host; @@ -71,10 +117,10 @@ static char *vty_accesslist_name = NULL; static char *vty_ipv6_accesslist_name = NULL; /* VTY server thread. */ -vector Vvty_serv_thread; +static vector Vvty_serv_thread; /* Current directory. */ -char *vty_cwd = NULL; +static char *vty_cwd = NULL; /* Configure lock. */ static int vty_config; @@ -89,29 +135,60 @@ static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; +/* Master of the threads. */ +static struct thread_master *master = NULL; +static qpn_nexus master_nexus = NULL; /* VTY standard output function. vty == NULL or VTY_SHELL => stdout */ int vty_out (struct vty *vty, const char *format, ...) { + int result; + + LOCK va_list args; + va_start (args, format); + result = uty_vout(vty, format, args); + va_end (args); + UNLOCK + return result; +} + +/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */ +static int +uty_out (struct vty *vty, const char *format, ...) +{ + int result; + ASSERTLOCKED + va_list args; + va_start (args, format); + result = uty_vout(vty, format, args); + va_end (args); + return result; +} + +/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */ +static int +uty_vout(struct vty *vty, const char *format, va_list args) +{ int len = 0; int size = 1024; char buf[1024]; char *p = NULL; + va_list ac; + + ASSERTLOCKED - if (vty_shell (vty)) + if (uty_shell (vty)) { - va_start (args, format); vprintf (format, args); - va_end (args); } else { /* Try to write to initial buffer. */ - va_start (args, format); - len = vsnprintf (buf, sizeof buf, format, args); - va_end (args); + va_copy(ac, args); + len = vsnprintf (buf, sizeof buf, format, ac); + va_end(ac); /* Initial buffer is not enough. */ if (len < 0 || len >= size) @@ -125,11 +202,11 @@ vty_out (struct vty *vty, const char *format, ...) p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); if (! p) - return -1; + return -1; - va_start (args, format); - len = vsnprintf (p, size, format, args); - va_end (args); + va_copy(ac, args); + len = vsnprintf (p, size, format, ac); + va_end(ac); if (len > -1 && len < size) break; @@ -180,9 +257,11 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, int len; char buf[1024]; + ASSERTLOCKED + if (!ctl->already_rendered) { - ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); + ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } if (ctl->len+1 >= sizeof(buf)) @@ -213,7 +292,7 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, return -1; /* Fatal I/O error. */ vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: write failed to vty client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: write failed to vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); buffer_reset(vty->obuf); /* cannot call vty_close, because a parent routine may still try @@ -248,6 +327,15 @@ vty_time_print (struct vty *vty, int cr) void vty_hello (struct vty *vty) { + LOCK + uty_hello(vty); + UNLOCK +} + +static void +uty_hello (struct vty *vty) +{ + ASSERTLOCKED if (host.motdfile) { FILE *f; @@ -263,15 +351,15 @@ vty_hello (struct vty *vty) for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1)); s--); *s = '\0'; - vty_out (vty, "%s%s", buf, VTY_NEWLINE); + uty_out (vty, "%s%s", buf, VTY_NEWLINE); } fclose (f); } else - vty_out (vty, "MOTD file not found%s", VTY_NEWLINE); + uty_out (vty, "MOTD file not found%s", VTY_NEWLINE); } else if (host.motd) - vty_out (vty, host.motd); + uty_out (vty, "%s", host.motd); } /* Put out prompt and wait input from user. */ @@ -281,6 +369,8 @@ vty_prompt (struct vty *vty) struct utsname names; const char*hostname; + ASSERTLOCKED + if (vty->type == VTY_TERM) { hostname = host.name; @@ -289,7 +379,7 @@ vty_prompt (struct vty *vty) uname (&names); hostname = names.nodename; } - vty_out (vty, cmd_prompt (vty->node), hostname); + uty_out (vty, cmd_prompt (vty->node), hostname); } } @@ -298,7 +388,8 @@ static void vty_will_echo (struct vty *vty) { unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; - vty_out (vty, "%s", cmd); + ASSERTLOCKED + uty_out (vty, "%s", cmd); } /* Make suppress Go-Ahead telnet option. */ @@ -306,7 +397,8 @@ static void vty_will_suppress_go_ahead (struct vty *vty) { unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; - vty_out (vty, "%s", cmd); + ASSERTLOCKED + uty_out (vty, "%s", cmd); } /* Make don't use linemode over telnet. */ @@ -314,7 +406,8 @@ static void vty_dont_linemode (struct vty *vty) { unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; - vty_out (vty, "%s", cmd); + ASSERTLOCKED + uty_out (vty, "%s", cmd); } /* Use window size. */ @@ -322,7 +415,8 @@ static void vty_do_window_size (struct vty *vty) { unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; - vty_out (vty, "%s", cmd); + ASSERTLOCKED + uty_out (vty, "%s", cmd); } #if 0 /* Currently not used. */ @@ -331,21 +425,30 @@ static void vty_dont_lflow_ahead (struct vty *vty) { unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; - vty_out (vty, "%s", cmd); + ASSERTLOCKED + uty_out (vty, "%s", cmd); } #endif /* 0 */ /* Allocate new vty struct. */ struct vty * -vty_new () +vty_new (int fd) { - struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty)); + struct vty *vty = XCALLOC (MTYPE_VTY, sizeof (struct vty)); - new->obuf = buffer_new(0); /* Use default buffer size. */ - new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); - new->max = VTY_BUFSIZ; + vty->obuf = buffer_new(0); /* Use default buffer size. */ + vty->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); + vty->max = VTY_BUFSIZ; + vty->fd = fd; - return new; + if (master_nexus) + { + vty->qf = qps_file_init_new(vty->qf, NULL); + qps_add_file(master_nexus->selection, vty->qf, vty->fd, vty); + vty->qtr = qtimer_init_new(vty->qtr, master_nexus->pile, vty_timeout_r, vty); + } + + return vty; } /* Authentication of vty */ @@ -357,6 +460,8 @@ vty_auth (struct vty *vty, char *buf) int fail; char *crypt (const char *, const char *); + ASSERTLOCKED + switch (vty->node) { case AUTH_NODE: @@ -400,14 +505,14 @@ vty_auth (struct vty *vty, char *buf) { if (vty->node == AUTH_NODE) { - vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); + uty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); vty->status = VTY_CLOSE; } else { /* AUTH_ENABLE_NODE */ vty->fail = 0; - vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); + uty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE; } } @@ -422,6 +527,8 @@ vty_command (struct vty *vty, char *buf) vector vline; const char *protocolname; + ASSERTLOCKED + /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); @@ -437,20 +544,19 @@ vty_command (struct vty *vty, char *buf) GETRUSAGE(&before); #endif /* CONSUMED_TIME_CHECK */ + UNLOCK ret = cmd_execute_command (vline, vty, NULL, 0); + LOCK /* Get the name of the protocol if any */ - if (zlog_default) - protocolname = zlog_proto_names[zlog_default->protocol]; - else - protocolname = zlog_proto_names[ZLOG_NONE]; + protocolname = uzlog_get_proto_name(NULL); #ifdef CONSUMED_TIME_CHECK GETRUSAGE(&after); if ((realtime = thread_consumed_time(&after, &before, &cputime)) > CONSUMED_TIME_CHECK) /* Warn about CPU hog that must be fixed. */ - zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s", + uzlog(NULL, LOG_WARNING, "SLOW COMMAND: command took %lums (cpu time %lums): %s", realtime/1000, cputime/1000, buf); } #endif /* CONSUMED_TIME_CHECK */ @@ -460,16 +566,16 @@ vty_command (struct vty *vty, char *buf) { case CMD_WARNING: if (vty->type == VTY_FILE) - vty_out (vty, "Warning...%s", VTY_NEWLINE); + uty_out (vty, "Warning...%s", VTY_NEWLINE); break; case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); break; case CMD_ERR_NO_MATCH: - vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE); + uty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE); break; case CMD_ERR_INCOMPLETE: - vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); + uty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); break; } cmd_free_strvec (vline); @@ -484,6 +590,7 @@ static const char telnet_space_char = ' '; static void vty_write (struct vty *vty, const char *buf, size_t nbytes) { + ASSERTLOCKED if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) return; @@ -495,6 +602,7 @@ vty_write (struct vty *vty, const char *buf, size_t nbytes) static void vty_ensure (struct vty *vty, int length) { + ASSERTLOCKED if (vty->max <= length) { vty->max *= 2; @@ -509,6 +617,8 @@ vty_self_insert (struct vty *vty, char c) int i; int length; + ASSERTLOCKED + vty_ensure (vty, vty->length + 1); length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); @@ -526,6 +636,7 @@ vty_self_insert (struct vty *vty, char c) static void vty_self_insert_overwrite (struct vty *vty, char c) { + ASSERTLOCKED vty_ensure (vty, vty->length + 1); vty->buf[vty->cp++] = c; @@ -542,7 +653,11 @@ vty_self_insert_overwrite (struct vty *vty, char c) static void vty_insert_word_overwrite (struct vty *vty, char *str) { + int len = strlen (str); + + ASSERTLOCKED + vty_write (vty, str, len); strcpy (&vty->buf[vty->cp], str); vty->cp += len; @@ -553,6 +668,7 @@ vty_insert_word_overwrite (struct vty *vty, char *str) static void vty_forward_char (struct vty *vty) { + ASSERTLOCKED if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); @@ -564,6 +680,7 @@ vty_forward_char (struct vty *vty) static void vty_backward_char (struct vty *vty) { + ASSERTLOCKED if (vty->cp > 0) { vty->cp--; @@ -575,6 +692,7 @@ vty_backward_char (struct vty *vty) static void vty_beginning_of_line (struct vty *vty) { + ASSERTLOCKED while (vty->cp) vty_backward_char (vty); } @@ -583,6 +701,7 @@ vty_beginning_of_line (struct vty *vty) static void vty_end_of_line (struct vty *vty) { + ASSERTLOCKED while (vty->cp < vty->length) vty_forward_char (vty); } @@ -597,6 +716,8 @@ vty_history_print (struct vty *vty) { int length; + ASSERTLOCKED + vty_kill_line_from_beginning (vty); /* Get previous line from history buffer */ @@ -614,6 +735,8 @@ vty_next_line (struct vty *vty) { int try_index; + ASSERTLOCKED + if (vty->hp == vty->hindex) return; @@ -639,6 +762,8 @@ vty_previous_line (struct vty *vty) { int try_index; + ASSERTLOCKED + try_index = vty->hp; if (try_index == 0) try_index = VTY_MAXHIST - 1; @@ -657,6 +782,7 @@ vty_previous_line (struct vty *vty) static void vty_redraw_line (struct vty *vty) { + ASSERTLOCKED vty_write (vty, vty->buf, vty->length); vty->cp = vty->length; } @@ -665,6 +791,7 @@ vty_redraw_line (struct vty *vty) static void vty_forward_word (struct vty *vty) { + ASSERTLOCKED while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') vty_forward_char (vty); @@ -676,6 +803,7 @@ vty_forward_word (struct vty *vty) static void vty_backward_pure_word (struct vty *vty) { + ASSERTLOCKED while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') vty_backward_char (vty); } @@ -684,6 +812,7 @@ vty_backward_pure_word (struct vty *vty) static void vty_backward_word (struct vty *vty) { + ASSERTLOCKED while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_backward_char (vty); @@ -696,7 +825,8 @@ vty_backward_word (struct vty *vty) static void vty_down_level (struct vty *vty) { - vty_out (vty, "%s", VTY_NEWLINE); + ASSERTLOCKED + uty_out (vty, "%s", VTY_NEWLINE); (*config_exit_cmd.func)(NULL, vty, 0, NULL); vty_prompt (vty); vty->cp = 0; @@ -706,7 +836,8 @@ vty_down_level (struct vty *vty) static void vty_end_config (struct vty *vty) { - vty_out (vty, "%s", VTY_NEWLINE); + ASSERTLOCKED + uty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { @@ -734,7 +865,7 @@ vty_end_config (struct vty *vty) case KEYCHAIN_KEY_NODE: case MASC_NODE: case VTY_NODE: - vty_config_unlock (vty); + uty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: @@ -753,6 +884,8 @@ vty_delete_char (struct vty *vty) int i; int size; + ASSERTLOCKED + if (vty->length == 0) { vty_down_level (vty); @@ -782,6 +915,7 @@ vty_delete_char (struct vty *vty) static void vty_delete_backward_char (struct vty *vty) { + ASSERTLOCKED if (vty->cp == 0) return; @@ -796,6 +930,8 @@ vty_kill_line (struct vty *vty) int i; int size; + ASSERTLOCKED + size = vty->length - vty->cp; if (size == 0) @@ -814,6 +950,7 @@ vty_kill_line (struct vty *vty) static void vty_kill_line_from_beginning (struct vty *vty) { + ASSERTLOCKED vty_beginning_of_line (vty); vty_kill_line (vty); } @@ -822,6 +959,7 @@ vty_kill_line_from_beginning (struct vty *vty) static void vty_forward_kill_word (struct vty *vty) { + ASSERTLOCKED while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') vty_delete_char (vty); while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') @@ -832,6 +970,7 @@ vty_forward_kill_word (struct vty *vty) static void vty_backward_kill_word (struct vty *vty) { + ASSERTLOCKED while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_delete_backward_char (vty); while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') @@ -844,6 +983,8 @@ vty_transpose_chars (struct vty *vty) { char c1, c2; + ASSERTLOCKED + /* If length is short or point is near by the beginning of line then return. */ if (vty->length < 2 || vty->cp < 1) @@ -875,11 +1016,14 @@ vty_transpose_chars (struct vty *vty) static void vty_complete_command (struct vty *vty) { + int i; int ret; char **matched = NULL; vector vline; + ASSERTLOCKED + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) return; @@ -895,11 +1039,11 @@ vty_complete_command (struct vty *vty) cmd_free_strvec (vline); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); switch (ret) { case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); break; @@ -929,11 +1073,11 @@ vty_complete_command (struct vty *vty) for (i = 0; matched[i] != NULL; i++) { if (i != 0 && ((i % 6) == 0)) - vty_out (vty, "%s", VTY_NEWLINE); - vty_out (vty, "%-10s ", matched[i]); + uty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%-10s ", matched[i]); XFREE (MTYPE_TMP, matched[i]); } - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); @@ -957,11 +1101,13 @@ vty_describe_fold (struct vty *vty, int cmd_width, const char *cmd, *p; int pos; + ASSERTLOCKED + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; if (desc_width <= 0) { - vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); return; } @@ -978,12 +1124,12 @@ vty_describe_fold (struct vty *vty, int cmd_width, strncpy (buf, p, pos); buf[pos] = '\0'; - vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); cmd = ""; } - vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); XFREE (MTYPE_TMP, buf); } @@ -992,12 +1138,14 @@ vty_describe_fold (struct vty *vty, int cmd_width, static void vty_describe_command (struct vty *vty) { - int ret; + int ret; vector vline; vector describe; unsigned int i, width, desc_width; struct desc *desc, *desc_cr = NULL; + ASSERTLOCKED + vline = cmd_make_strvec (vty->buf); /* In case of '> ?'. */ @@ -1012,17 +1160,17 @@ vty_describe_command (struct vty *vty) describe = cmd_describe_command (vline, vty, &ret); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); /* Ambiguous error. */ switch (ret) { case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); goto out; break; case CMD_ERR_NO_MATCH: - vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); + uty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); goto out; break; } @@ -1062,18 +1210,18 @@ vty_describe_command (struct vty *vty) } if (!desc->str) - vty_out (vty, " %-s%s", + uty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) - vty_out (vty, " %-*s %s%s", width, + uty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, desc); #if 0 - vty_out (vty, " %-*s %s%s", width + uty_out (vty, " %-*s %s%s", width desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str ? desc->str : "", VTY_NEWLINE); #endif /* 0 */ @@ -1082,11 +1230,11 @@ vty_describe_command (struct vty *vty) if ((desc = desc_cr)) { if (!desc->str) - vty_out (vty, " %-s%s", + uty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) - vty_out (vty, " %-*s %s%s", width, + uty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else @@ -1105,6 +1253,7 @@ out: static void vty_clear_buf (struct vty *vty) { + ASSERTLOCKED memset (vty->buf, 0, vty->max); } @@ -1112,9 +1261,10 @@ vty_clear_buf (struct vty *vty) static void vty_stop_input (struct vty *vty) { + ASSERTLOCKED vty->cp = vty->length = 0; vty_clear_buf (vty); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { @@ -1137,7 +1287,7 @@ vty_stop_input (struct vty *vty) case KEYCHAIN_KEY_NODE: case MASC_NODE: case VTY_NODE: - vty_config_unlock (vty); + uty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: @@ -1156,6 +1306,8 @@ vty_hist_add (struct vty *vty) { int index; + ASSERTLOCKED + if (vty->length == 0) return; @@ -1191,46 +1343,48 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) #ifdef TELNET_OPTION_DEBUG int i; + ASSERTLOCKED + for (i = 0; i < nbytes; i++) { switch (buf[i]) { case IAC: - vty_out (vty, "IAC "); + uty_out (vty, "IAC "); break; case WILL: - vty_out (vty, "WILL "); + uty_out (vty, "WILL "); break; case WONT: - vty_out (vty, "WONT "); + uty_out (vty, "WONT "); break; case DO: - vty_out (vty, "DO "); + uty_out (vty, "DO "); break; case DONT: - vty_out (vty, "DONT "); + uty_out (vty, "DONT "); break; case SB: - vty_out (vty, "SB "); + uty_out (vty, "SB "); break; case SE: - vty_out (vty, "SE "); + uty_out (vty, "SE "); break; case TELOPT_ECHO: - vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); break; case TELOPT_SGA: - vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); break; case TELOPT_NAWS: - vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); break; default: - vty_out (vty, "%x ", buf[i]); + uty_out (vty, "%x ", buf[i]); break; } } - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); #endif /* TELNET_OPTION_DEBUG */ @@ -1255,11 +1409,11 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) { case TELOPT_NAWS: if (vty->sb_len != TELNET_NAWS_SB_LEN) - zlog_warn("RFC 1073 violation detected: telnet NAWS option " + uzlog(NULL, LOG_WARNING, "RFC 1073 violation detected: telnet NAWS option " "should send %d characters, but we received %lu", TELNET_NAWS_SB_LEN, (u_long)vty->sb_len); else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN) - zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, " + uzlog(NULL, LOG_ERR, "Bug detected: sizeof(vty->sb_buf) %lu < %d, " "too small to handle the telnet NAWS option", (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN); else @@ -1267,7 +1421,7 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]); vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]); #ifdef TELNET_OPTION_DEBUG - vty_out(vty, "TELNET NAWS window size negotiation completed: " + uty_out(vty, "TELNET NAWS window size negotiation completed: " "width %d, height %d%s", vty->width, vty->height, VTY_NEWLINE); #endif @@ -1324,6 +1478,7 @@ vty_execute (struct vty *vty) static void vty_escape_map (unsigned char c, struct vty *vty) { + ASSERTLOCKED switch (c) { case ('A'): @@ -1350,22 +1505,51 @@ vty_escape_map (unsigned char c, struct vty *vty) static void vty_buffer_reset (struct vty *vty) { + ASSERTLOCKED buffer_reset (vty->obuf); vty_prompt (vty); vty_redraw_line (vty); } -/* Read data via vty socket. */ +/* Callback: qpthreads., Read data via vty socket. */ +static void +vty_read_r (qps_file qf, void* file_info) +{ + int vty_sock = qf->fd; + struct vty *vty = (struct vty *)file_info; + + LOCK + + /* is this necessary? */ + qps_disable_modes(qf, qps_read_mbit); + uty_read(vty, vty_sock); + + UNLOCK +} + +/* Callback: threads. Read data via vty socket. */ static int vty_read (struct thread *thread) { - int i; - int nbytes; - unsigned char buf[VTY_READ_BUFSIZ]; - int vty_sock = THREAD_FD (thread); struct vty *vty = THREAD_ARG (thread); + int result ; + + LOCK + vty->t_read = NULL; + result = uty_read(vty, vty_sock); + + UNLOCK + return result; +} + +static int +uty_read (struct vty *vty, int vty_sock) +{ + int i; + int nbytes; + unsigned char buf[VTY_READ_BUFSIZ]; /* Read raw data from socket */ if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) @@ -1378,7 +1562,7 @@ vty_read (struct thread *thread) return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: read error on vty client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: read error on vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); } buffer_reset(vty->obuf); @@ -1526,7 +1710,7 @@ vty_read (struct thread *thread) break; case '\n': case '\r': - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); vty_execute (vty); break; case '\t': @@ -1556,32 +1740,66 @@ vty_read (struct thread *thread) /* Check status. */ if (vty->status == VTY_CLOSE) - vty_close (vty); + uty_close (vty); else { vty_event (VTY_WRITE, vty_sock, vty); vty_event (VTY_READ, vty_sock, vty); } + return 0; } -/* Flush buffer to the vty. */ +/* Callback: qpthreads. Flush buffer to the vty. */ +static void +vty_flush_r (qps_file qf, void* file_info) +{ + int vty_sock = qf->fd; + struct vty *vty = (struct vty *)file_info; + + LOCK + + qps_disable_modes(qf, qps_write_mbit); + + /* Temporary disable read thread. */ + if ((vty->lines == 0)) + { + qps_disable_modes(qf, qps_read_mbit); + } + + uty_flush(vty, vty_sock); + + UNLOCK +} + +/* Callback: threads. Flush buffer to the vty. */ static int vty_flush (struct thread *thread) { - int erase; - buffer_status_t flushrc; int vty_sock = THREAD_FD (thread); struct vty *vty = THREAD_ARG (thread); + int result; + LOCK vty->t_write = NULL; - /* Tempolary disable read thread. */ + /* Temporary disable read thread. */ if ((vty->lines == 0) && vty->t_read) { thread_cancel (vty->t_read); vty->t_read = NULL; } + result = uty_flush(vty, vty_sock); + + UNLOCK + return result; +} + +static int +uty_flush (struct vty *vty, int vty_sock) +{ + int erase; + buffer_status_t flushrc; /* Function execution continue. */ erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); @@ -1601,14 +1819,14 @@ vty_flush (struct thread *thread) { case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("buffer_flush failed on vty client fd %d, closing", + uzlog(NULL, LOG_WARNING, "buffer_flush failed on vty client fd %d, closing", vty->fd); buffer_reset(vty->obuf); - vty_close(vty); - return 0; + uty_close(vty); + break; case BUFFER_EMPTY: if (vty->status == VTY_CLOSE) - vty_close (vty); + uty_close (vty); else { vty->status = VTY_NORMAL; @@ -1633,9 +1851,10 @@ vty_create (int vty_sock, union sockunion *su) { struct vty *vty; + ASSERTLOCKED + /* Allocate new vty structure and set up default values. */ - vty = vty_new (); - vty->fd = vty_sock; + vty = vty_new (vty_sock); vty->type = VTY_TERM; vty->address = sockunion_su2str (su); if (no_password_check) @@ -1672,17 +1891,17 @@ vty_create (int vty_sock, union sockunion *su) /* Vty is not available if password isn't set. */ if (host.password == NULL && host.password_encrypt == NULL) { - vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + uty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); return NULL; } } /* Say hello to the world. */ - vty_hello (vty); + uty_hello (vty); if (! no_password_check) - vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + uty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); /* Setting up terminal. */ vty_will_echo (vty); @@ -1701,22 +1920,45 @@ vty_create (int vty_sock, union sockunion *su) return vty; } -/* Accept connection from the network. */ +/* Callback: qpthreads. Accept connection from the network. */ +static void +vty_accept_r (qps_file qf, void* file_info) +{ + LOCK + + int accept_sock = qf->fd; + uty_accept(accept_sock); + + UNLOCK +} + +/* Callback: threads. Accept connection from the network. */ static int vty_accept (struct thread *thread) { + int result; + + LOCK + + int accept_sock = THREAD_FD (thread); + result = uty_accept(accept_sock); + + UNLOCK + return result; +} + +static int +uty_accept (int accept_sock) +{ int vty_sock; struct vty *vty; union sockunion su; int ret; unsigned int on; - int accept_sock; struct prefix *p = NULL; struct access_list *acl = NULL; char *bufp; - accept_sock = THREAD_FD (thread); - /* We continue hearing vty socket. */ vty_event (VTY_SERV, accept_sock, NULL); @@ -1726,7 +1968,7 @@ vty_accept (struct thread *thread) vty_sock = sockunion_accept (accept_sock, &su); if (vty_sock < 0) { - zlog_warn ("can't accept vty socket : %s", safe_strerror (errno)); + uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno)); return -1; } set_nonblocking(vty_sock); @@ -1740,7 +1982,7 @@ vty_accept (struct thread *thread) (access_list_apply (acl, p) == FILTER_DENY)) { char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", + uzlog (NULL, LOG_INFO, "Vty connection refused from %s", (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); @@ -1749,7 +1991,6 @@ vty_accept (struct thread *thread) vty_event (VTY_SERV, accept_sock, NULL); prefix_free (p); - return 0; } } @@ -1762,7 +2003,7 @@ vty_accept (struct thread *thread) (access_list_apply (acl, p) == FILTER_DENY)) { char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", + uzlog (NULL, LOG_INFO, "Vty connection refused from %s", (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); @@ -1771,7 +2012,6 @@ vty_accept (struct thread *thread) vty_event (VTY_SERV, accept_sock, NULL); prefix_free (p); - return 0; } } @@ -1783,10 +2023,10 @@ vty_accept (struct thread *thread) ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); if (ret < 0) - zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", + uzlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", safe_strerror (errno)); - zlog (NULL, LOG_INFO, "Vty connection from %s", + uzlog (NULL, LOG_INFO, "Vty connection from %s", (bufp = sockunion_su2str (&su))); if (bufp) XFREE (MTYPE_TMP, bufp); @@ -1807,6 +2047,8 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) int sock; char port_str[BUFSIZ]; + ASSERTLOCKED + memset (&req, 0, sizeof (struct addrinfo)); req.ai_flags = AI_PASSIVE; req.ai_family = AF_UNSPEC; @@ -1862,6 +2104,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) } #endif /* HAVE_IPV6 && ! NRL */ +#if defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6) /* Make vty server socket. */ static void vty_serv_sock_family (const char* addr, unsigned short port, int family) @@ -1871,6 +2114,8 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) int accept_sock; void* naddr=NULL; + ASSERTLOCKED + memset (&su, 0, sizeof (union sockunion)); su.sa.sa_family = family; if(addr) @@ -1888,11 +2133,11 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) switch(inet_pton(family,addr,naddr)) { case -1: - zlog_err("bad address %s",addr); + uzlog(NULL, LOG_ERR, "bad address %s",addr); naddr=NULL; break; case 0: - zlog_err("error translating address %s: %s",addr,safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "error translating address %s: %s",addr,safe_strerror(errno)); naddr=NULL; } @@ -1909,7 +2154,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) ret = sockunion_bind (accept_sock, &su, port, naddr); if (ret < 0) { - zlog_warn("can't bind socket"); + uzlog(NULL, LOG_WARNING, "can't bind socket"); close (accept_sock); /* Avoid sd leak. */ return; } @@ -1926,6 +2171,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* Add vty server event. */ vty_event (VTY_SERV, accept_sock, NULL); } +#endif /* defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6) */ #ifdef VTYSH /* For sockaddr_un. */ @@ -1941,6 +2187,8 @@ vty_serv_un (const char *path) mode_t old_mask; struct zprivs_ids_t ids; + ASSERTLOCKED + /* First of all, unlink existing socket */ unlink (path); @@ -1951,7 +2199,7 @@ vty_serv_un (const char *path) sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "Cannot create unix stream socket: %s", safe_strerror(errno)); return; } @@ -1968,7 +2216,7 @@ vty_serv_un (const char *path) ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { - zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno)); + ulog(NULL, LOG_ERR, "Cannot bind path %s: %s", path, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } @@ -1976,7 +2224,7 @@ vty_serv_un (const char *path) ret = listen (sock, 5); if (ret < 0) { - zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "listen(fd %d) failed: %s", sock, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } @@ -1990,7 +2238,7 @@ vty_serv_un (const char *path) /* set group of socket */ if ( chown (path, -1, ids.gid_vty) ) { - zlog_err ("vty_serv_un: could chown socket, %s", + uzlog (NULL, LOG_ERR, "vty_serv_un: could chown socket, %s", safe_strerror (errno) ); } } @@ -2000,16 +2248,36 @@ vty_serv_un (const char *path) /* #define VTYSH_DEBUG 1 */ +/* Callback: qpthreads. Accept connection */ +void int +vtysh_accept_r (qps_file qf, void* file_info) +{ + int accept_sock = qf->fd; + LOCK + utysh_accept (accept_sock); + UNLOCK +} + +/* Callback: threads. Accept connection */ static int vtysh_accept (struct thread *thread) { - int accept_sock; + int accept_sock = THREAD_FD (thread); + LOCK + result = utysh_accept (accept_sock); + UNLOCK + return result; +} + +static int +utysh_accept (int accept_sock) +{ int sock; int client_len; struct sockaddr_un client; struct vty *vty; - accept_sock = THREAD_FD (thread); + ASSERTLOCKED vty_event (VTYSH_SERV, accept_sock, NULL); @@ -2021,13 +2289,13 @@ vtysh_accept (struct thread *thread) if (sock < 0) { - zlog_warn ("can't accept vty socket : %s", safe_strerror (errno)); + uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno)); return -1; } if (set_nonblocking(sock) < 0) { - zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking," + uzlog (NULL, LOG_WARNING, "vtysh_accept: could not set vty socket %d to non-blocking," " %s, closing", sock, safe_strerror (errno)); close (sock); return -1; @@ -2050,6 +2318,8 @@ vtysh_accept (struct thread *thread) static int vtysh_flush(struct vty *vty) { + ASSERTLOCKED + switch (buffer_flush_available(vty->obuf, vty->fd)) { case BUFFER_PENDING: @@ -2057,9 +2327,9 @@ vtysh_flush(struct vty *vty) break; case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd); + uzlog(NULL, LOG_WARNING, "%s: write error to fd %d, closing", __func__, vty->fd); buffer_reset(vty->obuf); - vty_close(vty); + uty_close(vty); return -1; break; case BUFFER_EMPTY: @@ -2068,21 +2338,48 @@ vtysh_flush(struct vty *vty) return 0; } +/* Callback: qpthreads., Read data via vty socket. */ +static void +vtysh_read_r (qps_file qf, void* file_info) +{ + int vty_sock = qf->fd; + struct vty *vty = (struct vty *)file_info; + + LOCK + + /* is this necessary? */ + qps_disable_modes(qf, qps_read_mbit); + utysh_read(vty, vty_soc); + + UNLOCK +} + +/* Callback: threads. Read data via vty socket. */ static int vtysh_read (struct thread *thread) { + int vty_sock = THREAD_FD (thread); + struct vty *vty = THREAD_ARG (thread); + int result; + + LOCK + + vty->t_read = NULL; + result = uty_read(vty, vty_soc); + + UNLOCK + return result; +} + +static int +utysh_read (struct vty *vty, int sock) +{ int ret; - int sock; int nbytes; - struct vty *vty; unsigned char buf[VTY_READ_BUFSIZ]; unsigned char *p; u_char header[4] = {0, 0, 0, 0}; - sock = THREAD_FD (thread); - vty = THREAD_ARG (thread); - vty->t_read = NULL; - if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0) { if (nbytes < 0) @@ -2093,11 +2390,11 @@ vtysh_read (struct thread *thread) return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: read failed on vtysh client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: read failed on vtysh client fd %d, closing: %s", __func__, sock, safe_strerror(errno)); } buffer_reset(vty->obuf); - vty_close (vty); + uty_close (vty); #ifdef VTYSH_DEBUG printf ("close vtysh\n"); #endif /* VTYSH_DEBUG */ @@ -2139,13 +2436,32 @@ vtysh_read (struct thread *thread) return 0; } +/* Callback: qpthraeds. Write */ +static void +vtysh_write_r (qps_file qf, void* file_info) +{ + struct vty *vty = (struct vty *)file_info; + + LOCK + + qps_disable_modes(qf, qps_write_mbit); + vtysh_flush(vty); + + UNLOCK +} + +//* Callback: thraeds. Write */ static int vtysh_write (struct thread *thread) { struct vty *vty = THREAD_ARG (thread); + LOCK + vty->t_write = NULL; vtysh_flush(vty); + + UNLOCK return 0; } @@ -2155,6 +2471,8 @@ vtysh_write (struct thread *thread) void vty_serv_sock (const char *addr, unsigned short port, const char *path) { + LOCK + /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) { @@ -2174,6 +2492,8 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path) #ifdef VTYSH vty_serv_un (path); #endif /* VTYSH */ + + UNLOCK } /* Close vty interface. Warning: call this only from functions that @@ -2183,8 +2503,18 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path) void vty_close (struct vty *vty) { + LOCK + uty_close(vty); + UNLOCK +} + +static void +uty_close (struct vty *vty) +{ int i; + ASSERTLOCKED + /* Cancel threads.*/ if (vty->t_read) thread_cancel (vty->t_read); @@ -2192,6 +2522,17 @@ vty_close (struct vty *vty) thread_cancel (vty->t_write); if (vty->t_timeout) thread_cancel (vty->t_timeout); + if (vty->qf) + { + qps_remove_file(vty->qf); + qps_file_free(vty->qf); + vty->qf = NULL; + } + if (vty->qtr) + { + qtimer_free(vty->qtr); + vty->qtr = NULL; + } /* Flush buffer. */ buffer_flush_all (vty->obuf, vty->fd); @@ -2217,29 +2558,48 @@ vty_close (struct vty *vty) XFREE (MTYPE_VTY, vty->buf); /* Check configure. */ - vty_config_unlock (vty); + uty_config_unlock (vty); /* OK free vty. */ XFREE (MTYPE_VTY, vty); } -/* When time out occur output message then close connection. */ +/* Callback: qpthreads. When time out occur output message then close connection. */ +static void +vty_timeout_r (qtimer qtr, void* timer_info, qtime_t when) +{ + struct vty *vty = (struct vty *)timer_info; + LOCK + qtimer_unset(qtr); + uty_timeout(vty); + UNLOCK +} + +/* Callback: threads. When time out occur output message then close connection. */ static int vty_timeout (struct thread *thread) { - struct vty *vty; - - vty = THREAD_ARG (thread); + int result; + struct vty *vty = THREAD_ARG (thread); + LOCK vty->t_timeout = NULL; + result = uty_timeout(vty); + UNLOCK + return result; +} + +static int +uty_timeout (struct vty *vty) +{ vty->v_timeout = 0; /* Clear buffer*/ buffer_reset (vty->obuf); - vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); + uty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); /* Close connection. */ vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); return 0; } @@ -2251,14 +2611,15 @@ vty_read_file (FILE *confp) int ret; struct vty *vty; - vty = vty_new (); - vty->fd = 0; /* stdout */ + vty = vty_new (0); /* stdout */ vty->type = VTY_TERM; vty->node = CONFIG_NODE; /* Execute configuration file */ ret = config_from_file (vty, confp); + LOCK + if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) @@ -2272,11 +2633,12 @@ vty_read_file (FILE *confp) } fprintf (stderr, "Error occured during reading below line.\n%s\n", vty->buf); - vty_close (vty); + uty_close (vty); exit (1); } - vty_close (vty); + uty_close (vty); + UNLOCK } static FILE * @@ -2409,7 +2771,7 @@ vty_read_config (char *config_file, { ret = stat (integrate_default, &conf_stat); if (ret >= 0) - return; + return; } #endif /* VTYSH */ @@ -2454,18 +2816,19 @@ vty_log (const char *level, const char *proto_str, unsigned int i; struct vty *vty; + ASSERTLOCKED + if (!vtyvec) return; - for (i = 0; i < vector_active (vtyvec); i++) - if ((vty = vector_slot (vtyvec, i)) != NULL) - if (vty->monitor) - { - va_list ac; - va_copy(ac, va); - vty_log_out (vty, level, proto_str, format, ctl, ac); - va_end(ac); - } + for (i = 0; i < vector_active (vtyvec); i++) + if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) + { + va_list ac; + va_copy(ac, va); + vty_log_out (vty, level, proto_str, format, ctl, ac); + va_end(ac); + } } /* Async-signal-safe version of vty_log for fixed strings. */ @@ -2497,17 +2860,32 @@ vty_log_fixed (const char *buf, size_t len) int vty_config_lock (struct vty *vty) { + int result; + LOCK if (vty_config == 0) { vty->config = 1; vty_config = 1; } - return vty->config; + result = vty->config; + UNLOCK + return result; } int vty_config_unlock (struct vty *vty) { + int result; + LOCK + result = uty_config_unlock(vty); + UNLOCK + return result; +} + +static int +uty_config_unlock (struct vty *vty) +{ + ASSERTLOCKED if (vty_config == 1 && vty->config == 1) { vty->config = 0; @@ -2516,14 +2894,23 @@ vty_config_unlock (struct vty *vty) return vty->config; } -/* Master of the threads. */ -static struct thread_master *master; - static void vty_event (enum event event, int sock, struct vty *vty) { + if (master_nexus) + vty_event_r(event, sock, vty); + else + vty_event_t(event, sock, vty); +} + +/* thread event setter */ +static void +vty_event_t (enum event event, int sock, struct vty *vty) + { struct thread *vty_serv_thread; + ASSERTLOCKED + switch (event) { case VTY_SERV: @@ -2556,7 +2943,7 @@ vty_event (enum event event, int sock, struct vty *vty) case VTY_WRITE: if (! vty->t_write) vty->t_write = thread_add_write (master, vty_flush, vty, sock); - break; + break; case VTY_TIMEOUT_RESET: if (vty->t_timeout) { @@ -2572,6 +2959,70 @@ vty_event (enum event event, int sock, struct vty *vty) } } +/* qpthreads event setter */ +static void +vty_event_r (enum event event, int sock, struct vty *vty) + { + + qps_file accept_file = NULL; + + ASSERTLOCKED + + switch (event) + { + case VTY_SERV: + accept_file = vector_get_item(Vvty_serv_thread, sock); + if (accept_file == NULL) + { + accept_file = qps_file_init_new(accept_file, NULL); + qps_add_file(master_nexus->selection, accept_file, sock, NULL); + vector_set_index(Vvty_serv_thread, sock, accept_file); + } + qps_enable_mode(accept_file, qps_read_mnum, vty_accept_r) ; + break; +#ifdef VTYSH + case VTYSH_SERV: + accept_file = vector_get_item(Vvty_serv_thread, sock); + if (accept_file == NULL) + { + accept_file = qps_file_init_new(accept_file, NULL); + qps_add_file(master, accept_file, sock, NULL); + vector_set_index(Vvty_serv_thread, sock, accept_file); + } + qps_enable_mode(accept_file, qps_read_mnum, vtysh_accept_r) ; + break; + case VTYSH_READ: + qps_enable_mode(vty->file, qps_read_mnum, vtysh_read_r) ; + break; + case VTYSH_WRITE: + qps_enable_mode(vty->file, qps_write_mnum, vtysh_write_r) ; + break; +#endif /* VTYSH */ + case VTY_READ: + qps_enable_mode(vty->qf, qps_read_mnum, vty_read_r) ; + + /* Time out treatment. */ + if (vty->v_timeout) + { + qtimer_set(vty->qtr, qt_add_monotonic(QTIME(vty->v_timeout)), NULL) ; + } + break; + case VTY_WRITE: + qps_enable_mode(vty->qf, qps_write_mnum, vty_flush_r) ; + break; + case VTY_TIMEOUT_RESET: + if (vty->v_timeout) + { + qtimer_set(vty->qtr, qt_add_monotonic(QTIME(vty->v_timeout)), NULL) ; + } + else + { + qtimer_unset(vty->qtr); + } + break; + } +} + DEFUN (config_who, config_who_cmd, "who", @@ -2605,6 +3056,8 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str) { unsigned long timeout = 0; + LOCK + /* min_str and sec_str are already checked by parser. So it must be all digit string. */ if (min_str) @@ -2619,7 +3072,7 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str) vty->v_timeout = timeout; vty_event (VTY_TIMEOUT_RESET, 0, vty); - + UNLOCK return CMD_SUCCESS; } @@ -2895,22 +3348,40 @@ vty_reset () unsigned int i; struct vty *vty; struct thread *vty_serv_thread; + qps_file qf; + + LOCK for (i = 0; i < vector_active (vtyvec); i++) if ((vty = vector_slot (vtyvec, i)) != NULL) { buffer_reset (vty->obuf); vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); } - for (i = 0; i < vector_active (Vvty_serv_thread); i++) - if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) - { - thread_cancel (vty_serv_thread); - vector_slot (Vvty_serv_thread, i) = NULL; - close (i); - } + if (master_nexus) + { + for (i = 0; i < vector_active (Vvty_serv_thread); i++) + if ((qf = vector_slot (Vvty_serv_thread, i)) != NULL) + { + qps_remove_file(qf); + qps_file_free(qf); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + } + else + { + assert(master); + for (i = 0; i < vector_active (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + } vty_timeout_val = VTY_TIMEOUT_DEFAULT; @@ -2925,6 +3396,7 @@ vty_reset () XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); vty_ipv6_accesslist_name = NULL; } + UNLOCK } static void @@ -2954,25 +3426,60 @@ vty_get_cwd () int vty_shell (struct vty *vty) { + LOCK + int result; + result = uty_shell (vty); + UNLOCK + return result; +} + +static int +uty_shell (struct vty *vty) +{ return ((vty == NULL) || (vty->type == VTY_SHELL)) ? 1 : 0; } int vty_shell_serv (struct vty *vty) { - return vty->type == VTY_SHELL_SERV ? 1 : 0; + LOCK + int result; + result = ((vty->type == VTY_SHELL_SERV) ? 1 : 0); + UNLOCK + return result; } void vty_init_vtysh () { + LOCK vtyvec = vector_init (0); + UNLOCK +} + +/* qpthreads: Install vty's own commands like `who' command. */ +void +vty_init_r (void) +{ + master_nexus = qpn_init_new(master_nexus); + vty_mutex = qpt_mutex_init(vty_mutex, qpt_mutex_quagga); + vty_init(NULL); +} + +/* create and execute our thread */ +void +vty_exec_r(void) +{ + if (master_nexus) + qpn_exec(master_nexus); } -/* Install vty's own commands like `who' command. */ +/* threads: Install vty's own commands like `who' command. */ void vty_init (struct thread_master *master_thread) { + LOCK + /* For further configuration read, preserve current directory. */ vty_save_cwd (); @@ -3014,11 +3521,18 @@ vty_init (struct thread_master *master_thread) install_element (VTY_NODE, &vty_ipv6_access_class_cmd); install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd); #endif /* HAVE_IPV6 */ + + UNLOCK } void vty_terminate (void) { + LOCK + + if (master_nexus) + master_nexus->terminate = 1; + if (vty_cwd) XFREE (MTYPE_TMP, vty_cwd); @@ -3028,4 +3542,12 @@ vty_terminate (void) vector_free (vtyvec); vector_free (Vvty_serv_thread); } + UNLOCK + + if (vty_mutex) + vty_mutex = qpt_mutex_destroy(vty_mutex, 1); } + +#undef LOCK +#undef UNLOCK +#undef ASSERTLOCKED |