diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vpp/app/vppctl.c | 247 |
1 files changed, 158 insertions, 89 deletions
diff --git a/src/vpp/app/vppctl.c b/src/vpp/app/vppctl.c index 31c9e43a770..98158ddb5b6 100644 --- a/src/vpp/app/vppctl.c +++ b/src/vpp/app/vppctl.c @@ -21,6 +21,9 @@ #include <termios.h> #include <unistd.h> #include <string.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> #define DEBUG 0 @@ -31,45 +34,57 @@ #include <arpa/telnet.h> -#include <vppinfra/mem.h> -#include <vppinfra/format.h> -#include <vppinfra/socket.h> - #define SOCKET_FILE "/run/vpp/cli.sock" volatile int window_resized = 0; struct termios orig_tio; static void -send_ttype (clib_socket_t * s, int is_interactive) +send_ttype (int sock_fd, int is_interactive) { char *term; + static char buf[2048]; + + /* wipe the buffer so there is no potential + * for inter-invocation leakage */ + memset (buf, 0, sizeof (buf)); term = is_interactive ? getenv ("TERM") : "vppctl"; if (term == NULL) term = "dumb"; - clib_socket_tx_add_formatted (s, "%c%c%c" "%c%s" "%c%c", - IAC, SB, TELOPT_TTYPE, 0, term, IAC, SE); - clib_socket_tx (s); + int len = snprintf (buf, sizeof (buf), + "%c%c%c" + "%c%s" + "%c%c", + IAC, SB, TELOPT_TTYPE, 0, term, IAC, SE); + send (sock_fd, buf, len, 0); } static void -send_naws (clib_socket_t * s) +send_naws (int sock_fd) { struct winsize ws; + static char buf[2048]; + memset (buf, 0, sizeof (buf)); if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) < 0) { - clib_unix_warning ("ioctl(TIOCGWINSZ)"); + fprintf (stderr, "ioctl(TIOCGWINSZ)"); return; } - clib_socket_tx_add_formatted (s, "%c%c%c" "%c%c%c%c" "%c%c", - IAC, SB, TELOPT_NAWS, - ws.ws_col >> 8, ws.ws_col & 0xff, - ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE); - clib_socket_tx (s); + int len = snprintf (buf, sizeof (buf), + "%c%c%c" + "%c%c%c%c" + "%c%c", + IAC, SB, TELOPT_NAWS, ws.ws_col >> 8, ws.ws_col & 0xff, + ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE); + int n_written = write (sock_fd, buf, len); + if (n_written < len) + { + perror ("send_naws"); + } } static void @@ -84,74 +99,82 @@ signal_handler_term (int signum) tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio); } -static u8 * -process_input (u8 * str, clib_socket_t * s, int is_interactive, - int *sent_ttype) +static int +process_input (int sock_fd, unsigned char *rx_buf, int rx_buf_len, + int is_interactive, int *sent_ttype) { int i = 0; + int j = 0; - while (i < vec_len (s->rx_buffer)) + while (i < rx_buf_len) { - if (s->rx_buffer[i] == IAC) + if (rx_buf[i] == IAC) { - if (s->rx_buffer[i + 1] == SB) + if (rx_buf[i + 1] == SB) { - u8 *sb = 0; - char opt = s->rx_buffer[i + 2]; + char opt = rx_buf[i + 2]; i += 3; - while (s->rx_buffer[i] != IAC) - vec_add1 (sb, s->rx_buffer[i++]); - #if DEBUG - clib_warning ("SB %s\n %U", TELOPT (opt), - format_hexdump, sb, vec_len (sb)); + if (rx_buf[i] != IAC) + { + fprintf (stderr, "SB "); + } + while (rx_buf[i] != IAC && i < rx_buf_len) + fprintf (stderr, "%02x ", rx_buf[i++]); + fprintf (stderr, "\n"); +#else + while (rx_buf[i] != IAC && i < rx_buf_len) + { + i++; + } #endif - vec_free (sb); i += 2; if (opt == TELOPT_TTYPE) { - send_ttype (s, is_interactive); + send_ttype (sock_fd, is_interactive); *sent_ttype = 1; } else if (is_interactive && opt == TELOPT_NAWS) - send_naws (s); + send_naws (sock_fd); } else { #if DEBUG - clib_warning ("IAC at %d, IAC %s %s", i, - TELCMD (s->rx_buffer[i + 1]), - TELOPT (s->rx_buffer[i + 2])); + fprintf (stderr, "IAC at %d, IAC %s %s", i, + TELCMD (rx_buf[i + 1]), TELOPT (rx_buf[i + 2])); #endif i += 3; } } else - vec_add1 (str, s->rx_buffer[i++]); + { + /* i is always the same or ahead of j, so at worst this is a no-op */ + rx_buf[j] = rx_buf[i]; + i++; + j++; + } } - vec_reset_length (s->rx_buffer); - return str; + return j; } int main (int argc, char *argv[]) { - clib_socket_t _s = { 0 }, *s = &_s; - clib_error_t *error = 0; struct epoll_event event; struct sigaction sa; struct termios tio; int efd = -1; - u8 *str = 0; - u8 *cmd = 0; + char *cmd = 0; + int cmd_len = 0; int do_quit = 0; int is_interactive = 0; int acked = 1; /* counts messages from VPP; starts at 1 */ int sent_ttype = 0; - - - clib_mem_init (0, 64ULL << 10); + char *sock_fname = SOCKET_FILE; + int sock_fd = -1; + int error = 0; + int arg = 0; /* process command line */ argc--; @@ -159,32 +182,56 @@ main (int argc, char *argv[]) if (argc > 1 && strncmp (argv[0], "-s", 2) == 0) { - s->config = argv[1]; + sock_fname = argv[1]; argc -= 2; argv += 2; } - else - s->config = SOCKET_FILE; - while (argc--) - cmd = format (cmd, "%s%c", (argv++)[0], argc ? ' ' : 0); + struct sockaddr_un saddr = { 0 }; + saddr.sun_family = AF_UNIX; + strncpy (saddr.sun_path, sock_fname, sizeof (saddr.sun_path)); - s->flags = CLIB_SOCKET_F_IS_CLIENT; + sock_fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock_fd < 0) + { + perror ("socket"); + exit (1); + } - error = clib_socket_init (s); - if (error) - goto done; + if (connect (sock_fd, (struct sockaddr *) &saddr, sizeof (saddr)) < 0) + { + perror ("connect"); + exit (1); + } + + for (arg = 0; arg < argc; arg++) + { + cmd_len += strlen (argv[arg]) + 1; + } + if (cmd_len > 0) + { + cmd_len++; // account for \n in the end + cmd = malloc (cmd_len); + while (argc--) + { + strncat (cmd, *argv++, cmd_len); + strncat (cmd, " ", cmd_len); + } + cmd[cmd_len - 2] = '\n'; + cmd[cmd_len - 1] = 0; + } is_interactive = isatty (STDIN_FILENO) && cmd == 0; if (is_interactive) { /* Capture terminal resize events */ - clib_memset (&sa, 0, sizeof (struct sigaction)); + memset (&sa, 0, sizeof (struct sigaction)); sa.sa_handler = signal_handler_winch; if (sigaction (SIGWINCH, &sa, 0) < 0) { - error = clib_error_return_unix (0, "sigaction"); + error = errno; + perror ("sigaction for SIGWINCH"); goto done; } @@ -192,14 +239,16 @@ main (int argc, char *argv[]) sa.sa_handler = signal_handler_term; if (sigaction (SIGTERM, &sa, 0) < 0) { - error = clib_error_return_unix (0, "sigaction"); + error = errno; + perror ("sigaction for SIGTERM"); goto done; } /* Save the original tty state so we can restore it later */ if (tcgetattr (STDIN_FILENO, &orig_tio) < 0) { - error = clib_error_return_unix (0, "tcgetattr"); + error = errno; + perror ("tcgetattr"); goto done; } @@ -212,7 +261,8 @@ main (int argc, char *argv[]) if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &tio) < 0) { - error = clib_error_return_unix (0, "tcsetattr"); + error = errno; + perror ("tcsetattr"); goto done; } } @@ -227,28 +277,33 @@ main (int argc, char *argv[]) /* ignore EPERM; it means stdin is something like /dev/null */ if (errno != EPERM) { - error = clib_error_return_unix (0, "epoll_ctl[%d]", STDIN_FILENO); + error = errno; + fprintf (stderr, "epoll_ctl[%d]", STDIN_FILENO); + perror (0); goto done; } } /* register socket */ event.events = EPOLLIN | EPOLLPRI | EPOLLERR; - event.data.fd = s->fd; - if (epoll_ctl (efd, EPOLL_CTL_ADD, s->fd, &event) != 0) + event.data.fd = sock_fd; + if (epoll_ctl (efd, EPOLL_CTL_ADD, sock_fd, &event) != 0) { - error = clib_error_return_unix (0, "epoll_ctl[%d]", s->fd); + error = errno; + fprintf (stderr, "epoll_ctl[%d]", sock_fd); + perror (0); goto done; } while (1) { int n; + static int sent_cmd = 0; if (window_resized) { window_resized = 0; - send_naws (s); + send_naws (sock_fd); } if ((n = epoll_wait (efd, &event, 1, -1)) < 0) @@ -257,7 +312,8 @@ main (int argc, char *argv[]) if (errno == EINTR) continue; - error = clib_error_return_unix (0, "epoll_wait"); + error = errno; + perror ("epoll_wait"); goto done; } @@ -275,31 +331,37 @@ main (int argc, char *argv[]) n = read (STDIN_FILENO, c, sizeof (c)); if (n > 0) { - memcpy (clib_socket_tx_add (s, n), c, n); - error = clib_socket_tx (s); + int n_written = write (sock_fd, c, n); + if (n_written < n) + error = errno; if (error) goto done; } else if (n < 0) - clib_warning ("read rv=%d", n); - else /* EOF */ + fprintf (stderr, "read rv=%d", n); + else /* EOF */ do_quit = 1; } - else if (event.data.fd == s->fd) + else if (event.data.fd == sock_fd) { - error = clib_socket_rx (s, 100); + unsigned char rx_buf[100]; + memset (rx_buf, 0, sizeof (rx_buf)); + int nread = recv (sock_fd, rx_buf, sizeof (rx_buf), 0); + + if (nread < 0) + error = errno; if (error) break; - if (clib_socket_rx_end_of_file (s)) + if (nread == 0) break; - str = process_input (str, s, is_interactive, &sent_ttype); + int len = process_input (sock_fd, rx_buf, nread, is_interactive, + &sent_ttype); - if (vec_len (str) > 0) + if (len > 0) { - int len = vec_len (str); - u8 *p = str, *q = str; + unsigned char *p = rx_buf, *q = rx_buf; while (len) { @@ -310,7 +372,8 @@ main (int argc, char *argv[]) n = write (STDOUT_FILENO, p, q - p); if (n < 0) { - error = clib_error_return_unix (0, "write"); + error = errno; + perror ("write"); goto done; } @@ -322,42 +385,49 @@ main (int argc, char *argv[]) len -= q - p; p = q; } - - vec_reset_length (str); } if (do_quit && do_quit < acked) { /* Ask the other end to close the connection */ - clib_socket_tx_add_formatted (s, "quit\n"); - clib_socket_tx (s); + char quit_str[] = "quit\n"; + int n = write (sock_fd, quit_str, strlen (quit_str)); + if (n < strlen (quit_str)) + { + error = errno; + perror ("write quit"); + } do_quit = 0; } - if (cmd && sent_ttype) + if (cmd && sent_ttype && !sent_cmd) { /* We wait until after the TELNET TTYPE option has been sent. * That is to make sure the session at the VPP end has switched * to line-by-line mode, and thus avoid prompts and echoing. * Note that it does also disable further TELNET option processing. */ - clib_socket_tx_add_formatted (s, "%s\n", cmd); - clib_socket_tx (s); - vec_free (cmd); + int n_written = write (sock_fd, cmd, strlen (cmd) + 1); + sent_cmd = 1; + if (n_written < strlen (cmd)) + { + error = errno; + perror ("write command"); + goto done; + } do_quit = acked; /* quit after the next response */ } } else { - error = clib_error_return (0, "unknown fd"); + error = errno; + perror ("unknown fd"); goto done; } } - error = clib_socket_close (s); + close (sock_fd); done: - vec_free (cmd); - vec_free (str); if (efd > -1) close (efd); @@ -366,7 +436,6 @@ done: if (error) { - clib_error_report (error); return 1; } |