2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <sys/socket.h>
18 #include <sys/epoll.h>
19 #include <sys/ioctl.h>
32 #include <arpa/telnet.h>
34 #include <vppinfra/mem.h>
35 #include <vppinfra/format.h>
36 #include <vppinfra/socket.h>
38 #define SOCKET_FILE "/run/vpp/cli.sock"
40 volatile int window_resized = 0;
41 struct termios orig_tio;
44 send_ttype (clib_socket_t * s, int is_dumb)
46 clib_socket_tx_add_formatted (s, "%c%c%c" "%c%s" "%c%c",
47 IAC, SB, TELOPT_TTYPE,
48 0, is_dumb ? "dumb" : getenv ("TERM"),
54 send_naws (clib_socket_t * s)
58 if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
60 clib_unix_warning ("ioctl(TIOCGWINSZ)");
64 clib_socket_tx_add_formatted (s, "%c%c%c" "%c%c%c%c" "%c%c",
66 ws.ws_col >> 8, ws.ws_col & 0xff,
67 ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE);
72 signal_handler_winch (int signum)
78 signal_handler_term (int signum)
80 tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
84 process_input (u8 * str, clib_socket_t * s, int is_interactive)
88 while (i < vec_len (s->rx_buffer))
90 if (s->rx_buffer[i] == IAC)
92 if (s->rx_buffer[i + 1] == SB)
95 char opt = s->rx_buffer[i + 2];
97 while (s->rx_buffer[i] != IAC)
98 vec_add1 (sb, s->rx_buffer[i++]);
101 clib_warning ("SB %s\n %U", TELOPT (opt),
102 format_hexdump, sb, vec_len (sb));
106 if (opt == TELOPT_TTYPE)
107 send_ttype (s, !is_interactive);
108 else if (is_interactive && opt == TELOPT_NAWS)
114 clib_warning ("IAC at %d, IAC %s %s", i,
115 TELCMD (s->rx_buffer[i + 1]),
116 TELOPT (s->rx_buffer[i + 2]));
122 vec_add1 (str, s->rx_buffer[i++]);
124 vec_reset_length (s->rx_buffer);
130 main (int argc, char *argv[])
132 clib_socket_t _s = { 0 }, *s = &_s;
133 clib_error_t *error = 0;
134 struct epoll_event event;
143 clib_mem_init (0, 64ULL << 10);
145 /* process command line */
149 if (argc > 1 && strcmp (argv[0], "-s") == 0)
156 s->config = SOCKET_FILE;
159 cmd = format (cmd, "%s%c", (argv++)[0], argc ? ' ' : 0);
161 s->flags = SOCKET_IS_CLIENT;
163 error = clib_socket_init (s);
167 /* Capture terminal resize events */
168 memset (&sa, 0, sizeof (struct sigaction));
169 sa.sa_handler = signal_handler_winch;
171 if (sigaction (SIGWINCH, &sa, 0) < 0)
173 error = clib_error_return_unix (0, "sigaction");
177 sa.sa_handler = signal_handler_term;
178 if (sigaction (SIGTERM, &sa, 0) < 0)
180 error = clib_error_return_unix (0, "sigaction");
184 /* Save the original tty state so we can restore it later */
185 tcgetattr (STDIN_FILENO, &orig_tio);
187 /* Tweak the tty settings */
189 /* echo off, canonical mode off, ext'd input processing off */
190 tio.c_lflag &= ~(ECHO | ICANON | IEXTEN);
191 tio.c_cc[VMIN] = 1; /* 1 byte at a time */
192 tio.c_cc[VTIME] = 0; /* no timer */
193 tcsetattr (STDIN_FILENO, TCSAFLUSH, &tio);
195 efd = epoll_create1 (0);
198 event.events = EPOLLIN | EPOLLPRI | EPOLLERR;
199 event.data.fd = STDIN_FILENO;
200 if (epoll_ctl (efd, EPOLL_CTL_ADD, STDIN_FILENO, &event) != 0)
202 error = clib_error_return_unix (0, "epoll_ctl[%d]", STDIN_FILENO);
206 /* register socket */
207 event.events = EPOLLIN | EPOLLPRI | EPOLLERR;
208 event.data.fd = s->fd;
209 if (epoll_ctl (efd, EPOLL_CTL_ADD, s->fd, &event) != 0)
211 error = clib_error_return_unix (0, "epoll_ctl[%d]", s->fd);
225 if ((n = epoll_wait (efd, &event, 1, -1)) < 0)
227 /* maybe we received signal */
231 error = clib_error_return_unix (0, "epoll_wait");
238 if (event.data.fd == STDIN_FILENO)
243 n = read (STDIN_FILENO, c, sizeof (c));
246 memcpy (clib_socket_tx_add (s, n), c, n);
247 error = clib_socket_tx (s);
252 clib_warning ("read rv=%d", n);
254 else if (event.data.fd == s->fd)
256 error = clib_socket_rx (s, 100);
260 if (clib_socket_rx_end_of_file (s))
263 str = process_input (str, s, cmd == 0);
265 if (vec_len (str) > 0)
267 n = write (STDOUT_FILENO, str, vec_len (str));
270 error = clib_error_return_unix (0, "write");
273 vec_reset_length (str);
278 clib_socket_tx_add_formatted (s, "q\n");
284 clib_socket_tx_add_formatted (s, "%s\n", cmd);
292 error = clib_error_return (0, "unknown fd");
297 error = clib_socket_close (s);
307 clib_error_report (error);
310 tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
317 * fd.io coding-style-patch-verification: ON
320 * eval: (c-set-style "gnu")