ui_common.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * ui_common.c
  3. *
  4. *
  5. */
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include "addr_hash.h"
  10. #include "serv_hash.h"
  11. #include "iftop.h"
  12. #include "resolver.h"
  13. #include "sorted_list.h"
  14. #include "options.h"
  15. #include "ui_common.h"
  16. /* 2, 10 and 40 seconds */
  17. int history_divs[HISTORY_DIVISIONS] = {1, 5, 20};
  18. #define UNIT_DIVISIONS 4
  19. char* unit_bits[UNIT_DIVISIONS] = { "b", "Kb", "Mb", "Gb"};
  20. char* unit_bytes[UNIT_DIVISIONS] = { "B", "KB", "MB", "GB"};
  21. extern hash_type* history;
  22. extern int history_pos;
  23. extern int history_len;
  24. /*
  25. * Compare two screen lines based on bandwidth. Start comparing from the
  26. * specified column
  27. */
  28. int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) {
  29. int i;
  30. switch(options.linedisplay) {
  31. case OPTION_LINEDISPLAY_ONE_LINE_SENT:
  32. for(i = start_div; i < HISTORY_DIVISIONS; i++) {
  33. if(aa->sent[i] != bb->sent[i]) {
  34. return(aa->sent[i] < bb->sent[i]);
  35. }
  36. }
  37. break;
  38. case OPTION_LINEDISPLAY_ONE_LINE_RECV:
  39. for(i = start_div; i < HISTORY_DIVISIONS; i++) {
  40. if(aa->recv[i] != bb->recv[i]) {
  41. return(aa->recv[i] < bb->recv[i]);
  42. }
  43. }
  44. break;
  45. case OPTION_LINEDISPLAY_TWO_LINE:
  46. case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
  47. /* fallback to the combined sent+recv that also act as fallback for sent/recv */
  48. break;
  49. }
  50. for(i = start_div; i < HISTORY_DIVISIONS; i++) {
  51. if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) {
  52. return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]);
  53. }
  54. }
  55. return 1;
  56. }
  57. /*
  58. * Compare two screen lines based on hostname / IP. Fall over to compare by
  59. * bandwidth.
  60. */
  61. int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) {
  62. char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH];
  63. int r;
  64. /* This isn't overly efficient because we resolve again before
  65. display. */
  66. if (options.dnsresolution) {
  67. resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH);
  68. resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH);
  69. }
  70. else {
  71. inet_ntop(aa->ap.af, a, hosta, sizeof(hosta));
  72. inet_ntop(bb->ap.af, b, hostb, sizeof(hostb));
  73. }
  74. r = strcmp(hosta, hostb);
  75. if(r == 0) {
  76. return screen_line_bandwidth_compare(aa, bb, 2);
  77. }
  78. else {
  79. return (r > 0);
  80. }
  81. }
  82. /*
  83. * Compare two screen lines based on the sorting options selected.
  84. */
  85. int screen_line_compare(void* a, void* b) {
  86. host_pair_line* aa = (host_pair_line*)a;
  87. host_pair_line* bb = (host_pair_line*)b;
  88. if(options.sort == OPTION_SORT_DIV1) {
  89. return screen_line_bandwidth_compare(aa, bb, 0);
  90. }
  91. else if(options.sort == OPTION_SORT_DIV2) {
  92. return screen_line_bandwidth_compare(aa, bb, 1);
  93. }
  94. else if(options.sort == OPTION_SORT_DIV3) {
  95. return screen_line_bandwidth_compare(aa, bb, 2);
  96. }
  97. else if(options.sort == OPTION_SORT_SRC) {
  98. return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb);
  99. }
  100. else if(options.sort == OPTION_SORT_DEST) {
  101. return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb);
  102. }
  103. return 1;
  104. }
  105. /*
  106. * Format a data size in human-readable format
  107. */
  108. void readable_size(float n, char* buf, int bsize, int ksize, int bytes) {
  109. int i = 0;
  110. float size = 1;
  111. /* Convert to bits? */
  112. if(bytes == 0) {
  113. n *= 8;
  114. }
  115. while(1) {
  116. if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) {
  117. snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
  118. break;
  119. }
  120. i++;
  121. size *= ksize;
  122. if(n < size * 10) {
  123. snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
  124. break;
  125. }
  126. else if(n < size * 100) {
  127. snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
  128. break;
  129. }
  130. }
  131. }
  132. int history_length(const int d) {
  133. if (history_len < history_divs[d])
  134. return history_len * RESOLUTION;
  135. else
  136. return history_divs[d] * RESOLUTION;
  137. }
  138. void screen_list_init() {
  139. screen_list.compare = &screen_line_compare;
  140. sorted_list_initialise(&screen_list);
  141. }
  142. void screen_list_clear() {
  143. sorted_list_node* nn = NULL;
  144. peaksent = peakrecv = peaktotal = 0;
  145. while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
  146. free(nn->data);
  147. }
  148. sorted_list_destroy(&screen_list);
  149. }
  150. /*
  151. * Calculate peaks and totals
  152. */
  153. void calculate_totals() {
  154. int i;
  155. for(i = 0; i < HISTORY_LENGTH; i++) {
  156. int j;
  157. int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
  158. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  159. if(i < history_divs[j]) {
  160. totals.recv[j] += history_totals.recv[ii];
  161. totals.sent[j] += history_totals.sent[ii];
  162. }
  163. }
  164. if(history_totals.recv[i] > peakrecv) {
  165. peakrecv = history_totals.recv[i];
  166. }
  167. if(history_totals.sent[i] > peaksent) {
  168. peaksent = history_totals.sent[i];
  169. }
  170. if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) {
  171. peaktotal = history_totals.recv[i] + history_totals.sent[i];
  172. }
  173. }
  174. for(i = 0; i < HISTORY_DIVISIONS; i++) {
  175. int t = history_length(i);
  176. totals.recv[i] /= t;
  177. totals.sent[i] /= t;
  178. }
  179. }
  180. void make_screen_list() {
  181. hash_node_type* n = NULL;
  182. while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
  183. host_pair_line* line = (host_pair_line*)n->rec;
  184. int i;
  185. for(i = 0; i < HISTORY_DIVISIONS; i++) {
  186. line->recv[i] /= history_length(i);
  187. line->sent[i] /= history_length(i);
  188. }
  189. /* Don't make a new, sorted screen list if order is frozen
  190. */
  191. if(!options.freezeorder) {
  192. sorted_list_insert(&screen_list, line);
  193. }
  194. }
  195. }
  196. /*
  197. * Zeros all data in the screen hash, but does not remove items.
  198. */
  199. void screen_hash_clear() {
  200. hash_node_type* n = NULL;
  201. while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
  202. host_pair_line* hpl = (host_pair_line*)n->rec;
  203. hpl->total_recv = hpl->total_sent = 0;
  204. memset(hpl->recv, 0, sizeof(hpl->recv));
  205. memset(hpl->sent, 0, sizeof(hpl->sent));
  206. }
  207. }
  208. void analyse_data() {
  209. hash_node_type* n = NULL;
  210. if(options.paused == 1) {
  211. return;
  212. }
  213. // Zero totals
  214. memset(&totals, 0, sizeof totals);
  215. if(options.freezeorder) {
  216. screen_hash_clear();
  217. }
  218. else {
  219. screen_list_clear();
  220. hash_delete_all(screen_hash);
  221. }
  222. while(hash_next_item(history, &n) == HASH_STATUS_OK) {
  223. history_type* d = (history_type*)n->rec;
  224. host_pair_line* screen_line;
  225. union {
  226. host_pair_line **h_p_l_pp;
  227. void **void_pp;
  228. } u_screen_line = { &screen_line };
  229. addr_pair ap;
  230. int i;
  231. int tsent, trecv;
  232. tsent = trecv = 0;
  233. ap = *(addr_pair*)n->key;
  234. /* Aggregate hosts, if required */
  235. if(options.aggregate_src) {
  236. memset(&ap.src6, '\0', sizeof(ap.src6));
  237. }
  238. if(options.aggregate_dest) {
  239. memset(&ap.dst6, '\0', sizeof(ap.dst6));
  240. }
  241. /* Aggregate ports, if required */
  242. if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) {
  243. ap.src_port = 0;
  244. }
  245. if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) {
  246. ap.dst_port = 0;
  247. }
  248. if(options.showports == OPTION_PORTS_OFF) {
  249. ap.protocol = 0;
  250. }
  251. if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
  252. screen_line = xcalloc(1, sizeof *screen_line);
  253. hash_insert(screen_hash, &ap, screen_line);
  254. screen_line->ap = ap;
  255. }
  256. screen_line->total_sent += d->total_sent;
  257. screen_line->total_recv += d->total_recv;
  258. for(i = 0; i < HISTORY_LENGTH; i++) {
  259. int j;
  260. int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
  261. for(j = 0; j < HISTORY_DIVISIONS; j++) {
  262. if(i < history_divs[j]) {
  263. screen_line->recv[j] += d->recv[ii];
  264. screen_line->sent[j] += d->sent[ii];
  265. }
  266. }
  267. }
  268. }
  269. make_screen_list();
  270. calculate_totals();
  271. }
  272. void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star) {
  273. char hostname[HOSTNAME_LENGTH];
  274. char service[HOSTNAME_LENGTH];
  275. char* s_name;
  276. union {
  277. char **ch_pp;
  278. void **void_pp;
  279. } u_s_name = { &s_name };
  280. ip_service skey;
  281. int left;
  282. if(IN6_IS_ADDR_UNSPECIFIED(addr) && unspecified_as_star) {
  283. sprintf(hostname, " * ");
  284. }
  285. else {
  286. if (options.dnsresolution)
  287. resolve(af, addr, hostname, L);
  288. else
  289. inet_ntop(af, addr, hostname, sizeof(hostname));
  290. }
  291. left = strlen(hostname);
  292. if(port != 0) {
  293. skey.port = port;
  294. skey.protocol = protocol;
  295. if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) {
  296. snprintf(service, HOSTNAME_LENGTH, ":%s", s_name);
  297. }
  298. else {
  299. snprintf(service, HOSTNAME_LENGTH, ":%d", port);
  300. }
  301. }
  302. else {
  303. service[0] = '\0';
  304. }
  305. /* If we're showing IPv6 addresses with a port number, put them in square
  306. * brackets. */
  307. if(port == 0 || af == AF_INET || L < 2) {
  308. sprintf(line, "%-*s", L, hostname);
  309. }
  310. else {
  311. sprintf(line, "[%-.*s]", L-2, hostname);
  312. left += 2;
  313. }
  314. if(left > (L - strlen(service))) {
  315. left = L - strlen(service);
  316. if(left < 0) {
  317. left = 0;
  318. }
  319. }
  320. sprintf(line + left, "%-*s", L-left, service);
  321. }