summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpdw <>2014-01-02 09:28:57 +0000
committerpdw <>2014-01-02 09:28:57 +0000
commite81c0d8aaef575e1caac208004376133907b01fa (patch)
tree15b9ee9cae550fe353e63cd7d55db914594c3d51
parentff057367f72f1d55e087fbc6c7d701cb1b154fa4 (diff)
downloadiftop-e81c0d8aaef575e1caac208004376133907b01fa.zip
Fix to avoid system call in text mode wherever possible.
Robert Scheck <robert@fedoraproject.org>
-rw-r--r--configure.in2
-rw-r--r--tui.c354
2 files changed, 355 insertions, 1 deletions
diff --git a/configure.in b/configure.in
index df91806..076e2d8 100644
--- a/configure.in
+++ b/configure.in
@@ -74,7 +74,7 @@ dnl Fairly generic checks.
dnl
dnl Checks for system headers.
-AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/sockio.h unistd.h)
+AC_CHECK_HEADERS([sgtty.h sys/ioctl.h sys/time.h sys/sockio.h termio.h termios.h unistd.h])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
diff --git a/tui.c b/tui.c
new file mode 100644
index 0000000..896451e
--- /dev/null
+++ b/tui.c
@@ -0,0 +1,354 @@
+/*
+ * tui.c:
+ *
+ * Based on ui.c from the original iftop sources.
+ *
+ * This user interface does not make use of curses. Instead, it prints its
+ * output to STDOUT. This output is activated by providing the '-t' flag.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#if defined(HAVE_TERMIOS_H)
+#include <termios.h>
+#elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#elif defined(HAVE_TERMIO_H)
+#include <sys/ioctl.h>
+#include <termio.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include "sorted_list.h"
+#include "options.h"
+#include "ui_common.h"
+
+/* Width of the host column in the output */
+#define PRINT_WIDTH 40
+
+
+/*
+ * UI print function
+ */
+void tui_print() {
+ sorted_list_node* nn = NULL;
+ char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
+ char buf0_10[10], buf1_10[10], buf2_10[10];
+ int j;
+ static char *label;
+ static char *labellong;
+ int l = 0;
+
+ if (!label) {
+ xfree(label);
+ label = (char *)calloc(PRINT_WIDTH + 1, 1);
+ }
+
+ if (!labellong) {
+ xfree(labellong);
+ labellong = (char *)calloc(PRINT_WIDTH + 1 + 9, 1);
+ }
+
+ if (options.paused ) {
+ return;
+ }
+
+ /* Headings */
+ snprintf(label, PRINT_WIDTH, "%-*s", PRINT_WIDTH, "Host name (port/service if enabled)");
+ printf("%s %s %10s %10s %10s %10s\n", " #", label, "last 2s", "last 10s", "last 40s", "cumulative");
+
+ /* Divider line */
+ for (j = 0; j < PRINT_WIDTH + 52; j++) {
+ printf("-");
+ }
+ printf("\n");
+
+ /* Traverse the list of all connections */
+ while((nn = sorted_list_next_item(&screen_list, nn)) != NULL && l < options.num_lines) {
+ /* Increment the line counter */
+ l++;
+
+ /* Get the connection information */
+ host_pair_line* screen_line = (host_pair_line*)nn->data;
+
+ /* Assemble host information */
+ sprint_host(host1, screen_line->ap.af, &(screen_line->ap.src6), screen_line->ap.src_port, screen_line->ap.protocol, PRINT_WIDTH, options.aggregate_src);
+ sprint_host(host2, screen_line->ap.af, &(screen_line->ap.dst6), screen_line->ap.dst_port, screen_line->ap.protocol, PRINT_WIDTH, options.aggregate_dest);
+
+ /* Send rate per connection */
+ printf("%4d %s%s", l, host1, " =>");
+ for(j = 0; j < HISTORY_DIVISIONS; j++) {
+ readable_size(screen_line->sent[j], buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ printf(" %10s", buf0_10);
+ }
+ /* Cumulative sent data per connection */
+ readable_size(screen_line->total_sent, buf0_10, 10, 1024, 1);
+ printf(" %10s\n", buf0_10);
+
+ /* Receive rate per connection */
+ printf(" %s%s", host2, " <=");
+ for(j = 0; j < HISTORY_DIVISIONS; j++) {
+ readable_size(screen_line->recv[j], buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ printf(" %10s", buf0_10);
+ }
+ /* Cumulative received data per connection */
+ readable_size(screen_line->total_recv, buf0_10, 10, 1024, 1);
+ printf(" %10s\n", buf0_10);
+ }
+
+ /* Divider line */
+ for (j = 0; j < PRINT_WIDTH + 52; j++) {
+ printf("-");
+ }
+ printf("\n");
+
+ /* Rate totals */
+ snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total send rate:");
+ printf("%s ", labellong);
+ for(j = 0; j < HISTORY_DIVISIONS; j++) {
+ readable_size((((host_pair_line *)&totals)->sent[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
+ }
+
+ snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total receive rate:");
+ printf("%s ", labellong);
+ for(j = 0; j < HISTORY_DIVISIONS; j++) {
+ readable_size((((host_pair_line *)&totals)->recv[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
+ }
+
+ snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total send and receive rate:");
+ printf("%s ", labellong);
+ for(j = 0; j < HISTORY_DIVISIONS; j++) {
+ readable_size((((host_pair_line *)&totals)->sent[j] + ((host_pair_line *)&totals)->recv[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
+ }
+
+ /* Divider line */
+ for (j = 0; j < PRINT_WIDTH + 52; j++) {
+ printf("-");
+ }
+ printf("\n");
+
+ /* Peak traffic */
+ snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Peak rate (sent/received/total):");
+ readable_size(peaksent / RESOLUTION, buf0_10, 10, 1024, options.bandwidth_in_bytes);
+ readable_size(peakrecv / RESOLUTION, buf1_10, 10, 1024, options.bandwidth_in_bytes);
+ readable_size(peaktotal / RESOLUTION, buf2_10, 10, 1024, options.bandwidth_in_bytes);
+ printf("%s %10s %10s %10s\n", labellong, buf0_10, buf1_10, buf2_10);
+
+ /* Cumulative totals */
+ snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Cumulative (sent/received/total):");
+ readable_size(history_totals.total_sent, buf0_10, 10, 1024, 1);
+ readable_size(history_totals.total_recv, buf1_10, 10, 1024, 1);
+ readable_size(history_totals.total_recv + history_totals.total_sent, buf2_10, 10, 1024, 1);
+ printf("%s %10s %10s %10s\n", labellong, buf0_10, buf1_10, buf2_10);
+
+ /* Double divider line */
+ for (j = 0; j < PRINT_WIDTH + 52; j++) {
+ printf("=");
+ }
+ printf("\n\n");
+}
+
+
+/*
+ * Text interface data structure initializations.
+ */
+void tui_init() {
+ screen_list_init();
+ screen_hash = addr_hash_create();
+ service_hash = serv_hash_create();
+ serv_hash_initialise(service_hash);
+
+ printf("Listening on %s\n", options.interface);
+}
+
+
+/*
+ * Tick function indicating screen refresh
+ */
+void tui_tick(int print) {
+ if (print) {
+ tui_print();
+ }
+}
+
+
+/*
+ * Main UI loop. Code any interactive character inputs here.
+ */
+void tui_loop() {
+ int i;
+ extern sig_atomic_t foad;
+
+#if defined(HAVE_TERMIOS_H)
+ struct termios new_termios, old_termios;
+
+ tcgetattr(STDIN_FILENO, &old_termios);
+ new_termios = old_termios;
+ new_termios.c_lflag &= ~(ICANON|ECHO);
+ new_termios.c_cc[VMIN] = 1;
+ new_termios.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
+#elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
+ struct sgttyb new_tty, old_tty;
+
+ ioctl(STDIN_FILENO, TIOCGETP, &old_tty);
+ new_tty = old_tty;
+ new_tty.sg_flags &= ~(ICANON|ECHO);
+ ioctl(STDIN_FILENO, TIOCSETP, &new_tty);
+#elif defined(HAVE_TERMIO_H)
+ struct termio new_termio, old_termio;
+
+ ioctl(0, TCGETA, &old_termio);
+ new_termio = old_termio;
+ new_termio.c_lflag &= ~(ICANON|ECHO);
+ new_termio.c_cc[VMIN] = 1;
+ new_termio.c_cc[VTIME] = 0;
+ ioctl(0, TCSETA, &new_termio);
+#else
+ system("/bin/stty cbreak -echo >/dev/null 2>&1");
+#endif
+
+ while ((i = getchar()) != 'q' && foad == 0) {
+ switch (i) {
+ case 'u':
+ tick(1);
+ break;
+ case 'n':
+ options.dnsresolution ^= 1;
+ printf("DNS resolution is %s.\n\n", options.dnsresolution ? "ON" : "OFF");
+ tick(1);
+ break;
+ case 'N':
+ options.portresolution ^= 1;
+ printf("Port resolution is %s.\n\n", options.portresolution ? "ON" : "OFF");
+ tick(1);
+ break;
+ case 's':
+ options.aggregate_src ^= 1;
+ printf("%s source host\n\n", options.aggregate_src ? "Hide" : "Show");
+ tick(1);
+ break;
+ case 'd':
+ options.aggregate_dest ^= 1;
+ printf("%s destination host\n\n", options.aggregate_dest ? "Hide" : "Show");
+ tick(1);
+ break;
+ case 'S':
+ if (options.showports == OPTION_PORTS_OFF) {
+ options.showports = OPTION_PORTS_SRC;
+ }
+ else if (options.showports == OPTION_PORTS_DEST) {
+ options.showports = OPTION_PORTS_ON;
+ }
+ else if(options.showports == OPTION_PORTS_ON) {
+ options.showports = OPTION_PORTS_DEST;
+ }
+ else {
+ options.showports = OPTION_PORTS_OFF;
+ }
+ printf("Showing ports:%s%s%s%s.\n\n",
+ options.showports == OPTION_PORTS_SRC ? " src" : "",
+ options.showports == OPTION_PORTS_DEST ? " dest" : "",
+ options.showports == OPTION_PORTS_ON ? " both" : "",
+ options.showports == OPTION_PORTS_OFF ? " none" : "");
+ tick(1);
+ break;
+ case 'D':
+ if (options.showports == OPTION_PORTS_OFF) {
+ options.showports = OPTION_PORTS_DEST;
+ }
+ else if (options.showports == OPTION_PORTS_SRC) {
+ options.showports = OPTION_PORTS_ON;
+ }
+ else if(options.showports == OPTION_PORTS_ON) {
+ options.showports = OPTION_PORTS_SRC;
+ }
+ else {
+ options.showports = OPTION_PORTS_OFF;
+ }
+ printf("Showing ports:%s%s%s%s.\n\n",
+ options.showports == OPTION_PORTS_SRC ? " src" : "",
+ options.showports == OPTION_PORTS_DEST ? " dest" : "",
+ options.showports == OPTION_PORTS_ON ? " both" : "",
+ options.showports == OPTION_PORTS_OFF ? " none" : "");
+ tick(1);
+ break;
+ case 'p':
+ options.showports =
+ (options.showports == OPTION_PORTS_OFF) ?
+ OPTION_PORTS_ON :
+ OPTION_PORTS_OFF;
+ printf("Showing ports:%s%s%s%s.\n\n",
+ options.showports == OPTION_PORTS_SRC ? " src" : "",
+ options.showports == OPTION_PORTS_DEST ? " dest" : "",
+ options.showports == OPTION_PORTS_ON ? " both" : "",
+ options.showports == OPTION_PORTS_OFF ? " none" : "");
+ tick(1);
+ break;
+ case 'P':
+ options.paused ^= 1;
+ if (options.paused) {
+ printf("Pausing... press 'P' again to continue.\n");
+ }
+ else {
+ printf("Continuing.\n\n");
+ tick(1);
+ }
+ break;
+ case 'o':
+ options.freezeorder ^= 1;
+ printf("Order %s.\n\n", options.freezeorder ? "frozen" : "unfrozen");
+ tick(1);
+ break;
+ case '1':
+ options.sort = OPTION_SORT_DIV1;
+ printf("Sorting by column 1.\n\n");
+ tick(1);
+ break;
+ case '2':
+ options.sort = OPTION_SORT_DIV2;
+ printf("Sorting by column 2.\n\n");
+ tick(1);
+ break;
+ case '3':
+ options.sort = OPTION_SORT_DIV3;
+ printf("Sorting by column 3.\n\n");
+ tick(1);
+ break;
+ case '<':
+ options.sort = OPTION_SORT_SRC;
+ printf("Sorting by column source.\n\n");
+ tick(1);
+ break;
+ case '>':
+ options.sort = OPTION_SORT_DEST;
+ printf("Sorting by column destination.\n\n");
+ tick(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+#if defined(HAVE_TERMIOS_H)
+ tcsetattr(STDIN_FILENO, TCSANOW, &old_termios);
+#elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
+ ioctl(0, TIOCSETP, &old_tty);
+#elif defined(HAVE_TERMIO_H)
+ ioctl(0, TCSETA, &old_termio);
+#else
+ system("/bin/stty -cbreak echo >/dev/null 2>&1");
+#endif
+}
+