tui.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * tui.c:
  3. *
  4. * Based on ui.c from the original iftop sources.
  5. *
  6. * This user interface does not make use of curses. Instead, it prints its
  7. * output to STDOUT. This output is activated by providing the '-t' flag.
  8. *
  9. */
  10. #include "config.h"
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <signal.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #if defined(HAVE_TERMIOS_H)
  17. #include <termios.h>
  18. #elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
  19. #include <sys/ioctl.h>
  20. #include <sgtty.h>
  21. #elif defined(HAVE_TERMIO_H)
  22. #include <sys/ioctl.h>
  23. #include <termio.h>
  24. #else
  25. #include <stdlib.h>
  26. #endif
  27. #include "sorted_list.h"
  28. #include "options.h"
  29. #include "ui_common.h"
  30. /* Width of the host column in the output */
  31. #define PRINT_WIDTH 40
  32. /*
  33. * UI print function
  34. */
  35. void tui_print() {
  36. sorted_list_node* nn = NULL;
  37. char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
  38. char buf0_10[10], buf1_10[10], buf2_10[10];
  39. int j;
  40. static char *label;
  41. static char *labellong;
  42. int l = 0;
  43. if (!label) {
  44. xfree(label);
  45. label = (char *)calloc(PRINT_WIDTH + 1, 1);
  46. }
  47. if (!labellong) {
  48. xfree(labellong);
  49. labellong = (char *)calloc(PRINT_WIDTH + 1 + 9, 1);
  50. }
  51. if (options.paused ) {
  52. return;
  53. }
  54. /* Headings */
  55. snprintf(label, PRINT_WIDTH, "%-*s", PRINT_WIDTH, "Host name (port/service if enabled)");
  56. printf("%s %s %10s %10s %10s %10s\n", " #", label, "last 2s", "last 10s", "last 40s", "cumulative");
  57. /* Divider line */
  58. for (j = 0; j < PRINT_WIDTH + 52; j++) {
  59. printf("-");
  60. }
  61. printf("\n");
  62. /* Traverse the list of all connections */
  63. while((nn = sorted_list_next_item(&screen_list, nn)) != NULL && l < options.num_lines) {
  64. /* Increment the line counter */
  65. l++;
  66. /* Get the connection information */
  67. host_pair_line* screen_line = (host_pair_line*)nn->data;
  68. /* Assemble host information */
  69. 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);
  70. 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);
  71. /* Send rate per connection */
  72. printf("%4d %s%s", l, host1, " =>");
  73. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  74. readable_size(screen_line->sent[j], buf0_10, 10, 1024, options.bandwidth_in_bytes);
  75. printf(" %10s", buf0_10);
  76. }
  77. /* Cumulative sent data per connection */
  78. readable_size(screen_line->total_sent, buf0_10, 10, 1024, 1);
  79. printf(" %10s\n", buf0_10);
  80. /* Receive rate per connection */
  81. printf(" %s%s", host2, " <=");
  82. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  83. readable_size(screen_line->recv[j], buf0_10, 10, 1024, options.bandwidth_in_bytes);
  84. printf(" %10s", buf0_10);
  85. }
  86. /* Cumulative received data per connection */
  87. readable_size(screen_line->total_recv, buf0_10, 10, 1024, 1);
  88. printf(" %10s\n", buf0_10);
  89. }
  90. /* Divider line */
  91. for (j = 0; j < PRINT_WIDTH + 52; j++) {
  92. printf("-");
  93. }
  94. printf("\n");
  95. /* Rate totals */
  96. snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total send rate:");
  97. printf("%s ", labellong);
  98. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  99. readable_size((((host_pair_line *)&totals)->sent[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
  100. printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
  101. }
  102. snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total receive rate:");
  103. printf("%s ", labellong);
  104. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  105. readable_size((((host_pair_line *)&totals)->recv[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
  106. printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
  107. }
  108. snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Total send and receive rate:");
  109. printf("%s ", labellong);
  110. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  111. readable_size((((host_pair_line *)&totals)->sent[j] + ((host_pair_line *)&totals)->recv[j]) , buf0_10, 10, 1024, options.bandwidth_in_bytes);
  112. printf("%10s%c", buf0_10, j == HISTORY_DIVISIONS - 1 ? '\n' : ' ');
  113. }
  114. /* Divider line */
  115. for (j = 0; j < PRINT_WIDTH + 52; j++) {
  116. printf("-");
  117. }
  118. printf("\n");
  119. /* Peak traffic */
  120. snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Peak rate (sent/received/total):");
  121. readable_size(peaksent / RESOLUTION, buf0_10, 10, 1024, options.bandwidth_in_bytes);
  122. readable_size(peakrecv / RESOLUTION, buf1_10, 10, 1024, options.bandwidth_in_bytes);
  123. readable_size(peaktotal / RESOLUTION, buf2_10, 10, 1024, options.bandwidth_in_bytes);
  124. printf("%s %10s %10s %10s\n", labellong, buf0_10, buf1_10, buf2_10);
  125. /* Cumulative totals */
  126. snprintf(labellong, PRINT_WIDTH + 9, "%-*s", PRINT_WIDTH + 9, "Cumulative (sent/received/total):");
  127. readable_size(history_totals.total_sent, buf0_10, 10, 1024, 1);
  128. readable_size(history_totals.total_recv, buf1_10, 10, 1024, 1);
  129. readable_size(history_totals.total_recv + history_totals.total_sent, buf2_10, 10, 1024, 1);
  130. printf("%s %10s %10s %10s\n", labellong, buf0_10, buf1_10, buf2_10);
  131. /* Double divider line */
  132. for (j = 0; j < PRINT_WIDTH + 52; j++) {
  133. printf("=");
  134. }
  135. printf("\n\n");
  136. }
  137. /*
  138. * Text interface data structure initializations.
  139. */
  140. void tui_init() {
  141. screen_list_init();
  142. screen_hash = addr_hash_create();
  143. service_hash = serv_hash_create();
  144. serv_hash_initialise(service_hash);
  145. printf("Listening on %s\n", options.interface);
  146. }
  147. /*
  148. * Tick function indicating screen refresh
  149. */
  150. void tui_tick(int print) {
  151. if (print) {
  152. tui_print();
  153. }
  154. }
  155. /*
  156. * Main UI loop. Code any interactive character inputs here.
  157. */
  158. void tui_loop() {
  159. int i;
  160. extern sig_atomic_t foad;
  161. #if defined(HAVE_TERMIOS_H)
  162. struct termios new_termios, old_termios;
  163. tcgetattr(STDIN_FILENO, &old_termios);
  164. new_termios = old_termios;
  165. new_termios.c_lflag &= ~(ICANON|ECHO);
  166. new_termios.c_cc[VMIN] = 1;
  167. new_termios.c_cc[VTIME] = 0;
  168. tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
  169. #elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
  170. struct sgttyb new_tty, old_tty;
  171. ioctl(STDIN_FILENO, TIOCGETP, &old_tty);
  172. new_tty = old_tty;
  173. new_tty.sg_flags &= ~(ICANON|ECHO);
  174. ioctl(STDIN_FILENO, TIOCSETP, &new_tty);
  175. #elif defined(HAVE_TERMIO_H)
  176. struct termio new_termio, old_termio;
  177. ioctl(0, TCGETA, &old_termio);
  178. new_termio = old_termio;
  179. new_termio.c_lflag &= ~(ICANON|ECHO);
  180. new_termio.c_cc[VMIN] = 1;
  181. new_termio.c_cc[VTIME] = 0;
  182. ioctl(0, TCSETA, &new_termio);
  183. #else
  184. system("/bin/stty cbreak -echo >/dev/null 2>&1");
  185. #endif
  186. while ((i = getchar()) != 'q' && foad == 0) {
  187. switch (i) {
  188. case 'u':
  189. tick(1);
  190. break;
  191. case 'n':
  192. options.dnsresolution ^= 1;
  193. printf("DNS resolution is %s.\n\n", options.dnsresolution ? "ON" : "OFF");
  194. tick(1);
  195. break;
  196. case 'N':
  197. options.portresolution ^= 1;
  198. printf("Port resolution is %s.\n\n", options.portresolution ? "ON" : "OFF");
  199. tick(1);
  200. break;
  201. case 's':
  202. options.aggregate_src ^= 1;
  203. printf("%s source host\n\n", options.aggregate_src ? "Hide" : "Show");
  204. tick(1);
  205. break;
  206. case 'd':
  207. options.aggregate_dest ^= 1;
  208. printf("%s destination host\n\n", options.aggregate_dest ? "Hide" : "Show");
  209. tick(1);
  210. break;
  211. case 'S':
  212. if (options.showports == OPTION_PORTS_OFF) {
  213. options.showports = OPTION_PORTS_SRC;
  214. }
  215. else if (options.showports == OPTION_PORTS_DEST) {
  216. options.showports = OPTION_PORTS_ON;
  217. }
  218. else if(options.showports == OPTION_PORTS_ON) {
  219. options.showports = OPTION_PORTS_DEST;
  220. }
  221. else {
  222. options.showports = OPTION_PORTS_OFF;
  223. }
  224. printf("Showing ports:%s%s%s%s.\n\n",
  225. options.showports == OPTION_PORTS_SRC ? " src" : "",
  226. options.showports == OPTION_PORTS_DEST ? " dest" : "",
  227. options.showports == OPTION_PORTS_ON ? " both" : "",
  228. options.showports == OPTION_PORTS_OFF ? " none" : "");
  229. tick(1);
  230. break;
  231. case 'D':
  232. if (options.showports == OPTION_PORTS_OFF) {
  233. options.showports = OPTION_PORTS_DEST;
  234. }
  235. else if (options.showports == OPTION_PORTS_SRC) {
  236. options.showports = OPTION_PORTS_ON;
  237. }
  238. else if(options.showports == OPTION_PORTS_ON) {
  239. options.showports = OPTION_PORTS_SRC;
  240. }
  241. else {
  242. options.showports = OPTION_PORTS_OFF;
  243. }
  244. printf("Showing ports:%s%s%s%s.\n\n",
  245. options.showports == OPTION_PORTS_SRC ? " src" : "",
  246. options.showports == OPTION_PORTS_DEST ? " dest" : "",
  247. options.showports == OPTION_PORTS_ON ? " both" : "",
  248. options.showports == OPTION_PORTS_OFF ? " none" : "");
  249. tick(1);
  250. break;
  251. case 'p':
  252. options.showports =
  253. (options.showports == OPTION_PORTS_OFF) ?
  254. OPTION_PORTS_ON :
  255. OPTION_PORTS_OFF;
  256. printf("Showing ports:%s%s%s%s.\n\n",
  257. options.showports == OPTION_PORTS_SRC ? " src" : "",
  258. options.showports == OPTION_PORTS_DEST ? " dest" : "",
  259. options.showports == OPTION_PORTS_ON ? " both" : "",
  260. options.showports == OPTION_PORTS_OFF ? " none" : "");
  261. tick(1);
  262. break;
  263. case 'P':
  264. options.paused ^= 1;
  265. if (options.paused) {
  266. printf("Pausing... press 'P' again to continue.\n");
  267. }
  268. else {
  269. printf("Continuing.\n\n");
  270. tick(1);
  271. }
  272. break;
  273. case 'o':
  274. options.freezeorder ^= 1;
  275. printf("Order %s.\n\n", options.freezeorder ? "frozen" : "unfrozen");
  276. tick(1);
  277. break;
  278. case '1':
  279. options.sort = OPTION_SORT_DIV1;
  280. printf("Sorting by column 1.\n\n");
  281. tick(1);
  282. break;
  283. case '2':
  284. options.sort = OPTION_SORT_DIV2;
  285. printf("Sorting by column 2.\n\n");
  286. tick(1);
  287. break;
  288. case '3':
  289. options.sort = OPTION_SORT_DIV3;
  290. printf("Sorting by column 3.\n\n");
  291. tick(1);
  292. break;
  293. case '<':
  294. options.sort = OPTION_SORT_SRC;
  295. printf("Sorting by column source.\n\n");
  296. tick(1);
  297. break;
  298. case '>':
  299. options.sort = OPTION_SORT_DEST;
  300. printf("Sorting by column destination.\n\n");
  301. tick(1);
  302. break;
  303. default:
  304. break;
  305. }
  306. }
  307. #if defined(HAVE_TERMIOS_H)
  308. tcsetattr(STDIN_FILENO, TCSANOW, &old_termios);
  309. #elif defined(HAVE_SGTTY_H) && defined(TIOCSETP)
  310. ioctl(0, TIOCSETP, &old_tty);
  311. #elif defined(HAVE_TERMIO_H)
  312. ioctl(0, TCSETA, &old_termio);
  313. #else
  314. system("/bin/stty -cbreak echo >/dev/null 2>&1");
  315. #endif
  316. }