Annotation of embedaddon/mtr/ui/report.c, revision 1.1.1.3
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
1.1.1.2 misho 14: You should have received a copy of the GNU General Public License along
15: with this program; if not, write to the Free Software Foundation, Inc.,
16: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1 misho 17: */
18:
19: #include "config.h"
20:
21: #include <sys/types.h>
22: #include <stdio.h>
23: #include <netdb.h>
24: #include <netinet/in.h>
25: #include <sys/socket.h>
26: #include <string.h>
27: #include <strings.h>
28: #include <time.h>
1.1.1.2 misho 29: #ifdef HAVE_JANSSON
30: #include <jansson.h>
31: #endif
32: #ifdef HAVE_ERROR_H
33: #include <error.h>
34: #else
35: #include "portability/error.h"
36: #endif
1.1 misho 37:
38: #include "mtr.h"
39: #include "report.h"
40: #include "net.h"
41: #include "dns.h"
42: #include "asn.h"
43: #include "utils.h"
44:
45: #define MAXLOADBAL 5
1.1.1.3 ! misho 46: #define MAX_FORMAT_STR 320
1.1 misho 47:
48:
49: void report_open(
50: void)
51: {
52: const time_t now = time(NULL);
53: const char *t = iso_time(&now);
54:
55: printf("Start: %s\n", t);
56: }
57:
58: static size_t snprint_addr(
59: struct mtr_ctl *ctl,
60: char *dst,
61: size_t dst_len,
62: ip_t * addr)
63: {
64: if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
65: struct hostent *host =
66: ctl->dns ? addr2host((void *) addr, ctl->af) : NULL;
67: if (!host)
1.1.1.3 ! misho 68: return snprintf(dst, dst_len, "%s", strlongip(ctl->af, addr));
1.1 misho 69: else if (ctl->dns && ctl->show_ips)
70: return snprintf(dst, dst_len, "%s (%s)", host->h_name,
1.1.1.3 ! misho 71: strlongip(ctl->af, addr));
1.1 misho 72: else
73: return snprintf(dst, dst_len, "%s", host->h_name);
74: } else
75: return snprintf(dst, dst_len, "%s", "???");
76: }
77:
78:
79: #ifdef HAVE_IPINFO
80: static void print_mpls(
81: struct mplslen *mpls)
82: {
83: int k;
84: for (k = 0; k < mpls->labels; k++)
1.1.1.2 misho 85: printf(" [MPLS: Lbl %lu TC %u S %cu TTL %u]\n",
86: mpls->label[k], mpls->tc[k], mpls->s[k], mpls->ttl[k]);
1.1 misho 87: }
88: #endif
89:
90: void report_close(
91: struct mtr_ctl *ctl)
92: {
93: int i, j, at, max, z, w;
94: struct mplslen *mpls, *mplss;
95: ip_t *addr;
96: ip_t *addr2 = NULL;
97: char name[MAX_FORMAT_STR];
98: char buf[1024];
99: char fmt[16];
100: size_t len = 0;
101: size_t len_hosts = 33;
102: #ifdef HAVE_IPINFO
103: int len_tmp;
104: const size_t iiwidth_len = get_iiwidth_len();
105: #endif
106:
107: if (ctl->reportwide) {
108: /* get the longest hostname */
109: len_hosts = strlen(ctl->LocalHostname);
110: max = net_max(ctl);
111: at = net_min(ctl);
112: for (; at < max; at++) {
113: size_t nlen;
114: addr = net_addr(at);
115: if ((nlen = snprint_addr(ctl, name, sizeof(name), addr)))
116: if (len_hosts < nlen)
117: len_hosts = nlen;
118: }
119: }
120: #ifdef HAVE_IPINFO
121: len_tmp = len_hosts;
122: if (ctl->ipinfo_no >= 0 && iiwidth_len) {
123: ctl->ipinfo_no %= iiwidth_len;
124: if (ctl->reportwide) {
125: len_hosts++; /* space */
126: len_tmp += get_iiwidth(ctl->ipinfo_no);
127: if (!ctl->ipinfo_no)
128: len_tmp += 2; /* align header: AS */
129: }
130: }
131: snprintf(fmt, sizeof(fmt), "HOST: %%-%ds", len_tmp);
132: #else
133: snprintf(fmt, sizeof(fmt), "HOST: %%-%zus", len_hosts);
134: #endif
135: snprintf(buf, sizeof(buf), fmt, ctl->LocalHostname);
136: len = ctl->reportwide ? strlen(buf) : len_hosts;
137: for (i = 0; i < MAXFLD; i++) {
138: j = ctl->fld_index[ctl->fld_active[i]];
139: if (j < 0)
140: continue;
141:
142: snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
143: snprintf(buf + len, sizeof(buf), fmt, data_fields[j].title);
144: len += data_fields[j].length;
145: }
146: printf("%s\n", buf);
147:
148: max = net_max(ctl);
149: at = net_min(ctl);
150: for (; at < max; at++) {
151: addr = net_addr(at);
152: mpls = net_mpls(at);
153: snprint_addr(ctl, name, sizeof(name), addr);
154:
155: #ifdef HAVE_IPINFO
156: if (is_printii(ctl)) {
157: snprintf(fmt, sizeof(fmt), " %%2d. %%s%%-%zus", len_hosts);
158: snprintf(buf, sizeof(buf), fmt, at + 1, fmt_ipinfo(ctl, addr),
159: name);
160: } else {
161: #endif
162: snprintf(fmt, sizeof(fmt), " %%2d.|-- %%-%zus", len_hosts);
163: snprintf(buf, sizeof(buf), fmt, at + 1, name);
164: #ifdef HAVE_IPINFO
165: }
166: #endif
167: len = ctl->reportwide ? strlen(buf) : len_hosts;
168: for (i = 0; i < MAXFLD; i++) {
169: j = ctl->fld_index[ctl->fld_active[i]];
170: if (j < 0)
171: continue;
172:
1.1.1.3 ! misho 173: /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */
1.1 misho 174: if (strchr(data_fields[j].format, 'f')) {
175: snprintf(buf + len, sizeof(buf), data_fields[j].format,
176: data_fields[j].net_xxx(at) / 1000.0);
177: } else {
178: snprintf(buf + len, sizeof(buf), data_fields[j].format,
179: data_fields[j].net_xxx(at));
180: }
181: len += data_fields[j].length;
182: }
183: printf("%s\n", buf);
184:
185: /* This feature shows 'loadbalances' on routes */
186:
1.1.1.2 misho 187: /* Print list of all hosts that have responded from ttl = at + 1 away */
188: for (z = 0; z < MAX_PATH; z++) {
1.1 misho 189: int found = 0;
190: addr2 = net_addrs(at, z);
191: mplss = net_mplss(at, z);
192: if ((addrcmp
193: ((void *) &ctl->unspec_addr, (void *) addr2,
1.1.1.2 misho 194: ctl->af)) == 0) {
1.1 misho 195: break;
1.1.1.2 misho 196: } else if ((addrcmp
197: ((void *) addr, (void *) addr2,
198: ctl->af)) == 0) {
199: continue; /* Latest Host is already printed */
200: } else {
201: snprint_addr(ctl, name, sizeof(name), addr2);
202: snprintf(fmt, sizeof(fmt), " %%-%zus", len_hosts);
203: snprintf(buf, sizeof(buf), fmt, name);
204: printf("%s\n", buf);
205: }
1.1 misho 206: for (w = 0; w < z; w++)
207: /* Ok... checking if there are ips repeated on same hop */
208: if ((addrcmp
209: ((void *) addr2, (void *) net_addrs(at, w),
210: ctl->af)) == 0) {
211: found = 1;
212: break;
213: }
214:
215: if (!found) {
216:
217: #ifdef HAVE_IPINFO
1.1.1.3 ! misho 218: if (mpls->labels && z == 1 && ctl->enablempls)
! 219: print_mpls(mpls);
1.1 misho 220: if (is_printii(ctl)) {
221: snprint_addr(ctl, name, sizeof(name), addr2);
222: printf(" %s%s\n", fmt_ipinfo(ctl, addr2), name);
223: }
1.1.1.3 ! misho 224: if (ctl->enablempls)
! 225: print_mpls(mplss);
1.1 misho 226: #else
227: int k;
228: if (mpls->labels && z == 1 && ctl->enablempls) {
229: for (k = 0; k < mpls->labels; k++) {
230: printf
1.1.1.2 misho 231: (" | |+-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
232: mpls->label[k], mpls->tc[k], mpls->s[k],
1.1 misho 233: mpls->ttl[k]);
234: }
235: }
236:
237: if (z == 1) {
1.1.1.3 ! misho 238: printf(" | `|-- %s\n", strlongip(ctl->af, addr2));
1.1 misho 239: for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
240: printf
1.1.1.2 misho 241: (" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
242: mplss->label[k], mplss->tc[k], mplss->s[k],
1.1 misho 243: mplss->ttl[k]);
244: }
245: } else {
1.1.1.3 ! misho 246: printf(" | |-- %s\n", strlongip(ctl->af, addr2));
1.1 misho 247: for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
248: printf
1.1.1.2 misho 249: (" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
250: mplss->label[k], mplss->tc[k], mplss->s[k],
1.1 misho 251: mplss->ttl[k]);
252: }
253: }
254: #endif
255: }
256: }
257:
258: /* No multipath */
259: #ifdef HAVE_IPINFO
260: if (is_printii(ctl)) {
261: if (mpls->labels && z == 1 && ctl->enablempls)
262: print_mpls(mpls);
263: }
264: #else
265: if (mpls->labels && z == 1 && ctl->enablempls) {
266: int k;
267: for (k = 0; k < mpls->labels; k++) {
1.1.1.2 misho 268: printf(" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
269: mpls->label[k], mpls->tc[k], mpls->s[k],
1.1 misho 270: mpls->ttl[k]);
271: }
272: }
273: #endif
274: }
275: }
276:
277:
278: void txt_open(
279: void)
280: {
281: }
282:
283:
284: void txt_close(
285: struct mtr_ctl *ctl)
286: {
287: report_close(ctl);
288: }
289:
1.1.1.2 misho 290: #ifdef HAVE_JANSSON
1.1 misho 291: void json_open(
292: void)
293: {
294: }
295:
1.1.1.2 misho 296: void json_close(struct mtr_ctl *ctl)
1.1 misho 297: {
1.1.1.2 misho 298: int i, j, at, max;
299: int ret;
300: char buf[128];
301: json_t *jreport, *jmtr, *jhubs, *jh;
1.1 misho 302: ip_t *addr;
303: char name[MAX_FORMAT_STR];
304:
1.1.1.2 misho 305: jmtr = json_pack("{ss ss si si}",
306: "src", ctl->LocalHostname,
307: "dst", ctl->Hostname,
308: "tos", ctl->tos,
309: "tests", ctl->MaxPing);
310: if (!jmtr)
311: goto on_error;
312:
1.1 misho 313: if (ctl->cpacketsize >= 0) {
1.1.1.2 misho 314: snprintf(buf, sizeof(buf), "%d", ctl->cpacketsize);
1.1 misho 315: } else {
1.1.1.2 misho 316: snprintf(buf, sizeof(buf), "rand(%d-%d)", MINPACKET, -ctl->cpacketsize);
1.1 misho 317: }
1.1.1.2 misho 318: ret = json_object_set_new(jmtr, "psize", json_string(buf));
319: if (ret == -1)
320: goto on_error;
321:
1.1 misho 322: if (ctl->bitpattern >= 0) {
1.1.1.2 misho 323: snprintf(buf, sizeof(buf), "0x%02X", (unsigned char)(ctl->bitpattern));
1.1 misho 324: } else {
1.1.1.2 misho 325: snprintf(buf, sizeof(buf), "rand(0x00-FF)");
1.1 misho 326: }
327:
1.1.1.2 misho 328: ret = json_object_set_new(jmtr, "bitpattern", json_string(buf));
329: if (ret == -1)
330: goto on_error;
331:
332: jhubs = json_array();
333: if (!jhubs)
334: goto on_error;
1.1 misho 335:
336: max = net_max(ctl);
1.1.1.2 misho 337: at = net_min(ctl);
1.1 misho 338: for (; at < max; at++) {
339: addr = net_addr(at);
340: snprint_addr(ctl, name, sizeof(name), addr);
341:
1.1.1.2 misho 342: jh = json_pack("{si ss}", "count", at + 1, "host", name);
343: if (!jh)
344: goto on_error;
345:
1.1 misho 346: #ifdef HAVE_IPINFO
1.1.1.3 ! misho 347: if (!ctl->ipinfo_no) {
1.1.1.2 misho 348: char* fmtinfo = fmt_ipinfo(ctl, addr);
349: if (fmtinfo != NULL)
350: fmtinfo = trim(fmtinfo, '\0');
351:
352: ret = json_object_set_new(jh, "ASN", json_string(fmtinfo));
353: if (ret == -1)
354: goto on_error;
1.1 misho 355: }
356: #endif
357:
1.1.1.2 misho 358: for (i = 0; i < MAXFLD; i++) {
1.1 misho 359: j = ctl->fld_index[ctl->fld_active[i]];
360:
361: if (j <= 0)
1.1.1.2 misho 362: continue; /* Field nr 0, " " shouldn't be printed in this method. */
1.1 misho 363:
364: if (strchr(data_fields[j].format, 'f')) {
1.1.1.2 misho 365: ret = json_object_set_new(
366: jh, data_fields[j].title,
367: json_real(data_fields[j].net_xxx(at) / 1000.0));
1.1 misho 368: } else {
1.1.1.2 misho 369: ret = json_object_set_new(
370: jh, data_fields[j].title,
371: json_integer(data_fields[j].net_xxx(at)));
1.1 misho 372: }
1.1.1.2 misho 373: if (ret == -1)
374: goto on_error;
1.1 misho 375: }
1.1.1.2 misho 376:
377: ret = json_array_append_new(jhubs, jh);
378: if (ret == -1)
379: goto on_error;
1.1 misho 380: }
381:
1.1.1.2 misho 382: jreport = json_pack("{s{so so}}", "report", "mtr", jmtr, "hubs", jhubs);
383:
384: ret = json_dumpf(jreport, stdout, JSON_INDENT(4) | JSON_REAL_PRECISION(5));
385: if (ret == -1)
386: goto on_error;
387:
1.1.1.3 ! misho 388: printf("\n"); // bash prompt should be on new line
1.1.1.2 misho 389: json_decref(jreport);
390: return;
391: on_error:
392: error(EXIT_FAILURE, 0, "json_close failed");
393: }
394: #endif
1.1 misho 395:
396:
397: void xml_open(
398: void)
399: {
400: }
401:
402:
403: void xml_close(
404: struct mtr_ctl *ctl)
405: {
406: int i, j, at, max;
407: ip_t *addr;
408: char name[MAX_FORMAT_STR];
409:
410: printf("<?xml version=\"1.0\"?>\n");
411: printf("<MTR SRC=\"%s\" DST=\"%s\"", ctl->LocalHostname,
412: ctl->Hostname);
413: printf(" TOS=\"0x%X\"", ctl->tos);
414: if (ctl->cpacketsize >= 0) {
415: printf(" PSIZE=\"%d\"", ctl->cpacketsize);
416: } else {
417: printf(" PSIZE=\"rand(%d-%d)\"", MINPACKET, -ctl->cpacketsize);
418: }
419: if (ctl->bitpattern >= 0) {
420: printf(" BITPATTERN=\"0x%02X\"",
421: (unsigned char) (ctl->bitpattern));
422: } else {
423: printf(" BITPATTERN=\"rand(0x00-FF)\"");
424: }
425: printf(" TESTS=\"%d\">\n", ctl->MaxPing);
426:
427: max = net_max(ctl);
428: at = net_min(ctl);
429: for (; at < max; at++) {
430: addr = net_addr(at);
431: snprint_addr(ctl, name, sizeof(name), addr);
432:
433: printf(" <HUB COUNT=\"%d\" HOST=\"%s\">\n", at + 1, name);
434: for (i = 0; i < MAXFLD; i++) {
435: const char *title;
436:
437: j = ctl->fld_index[ctl->fld_active[i]];
438: if (j <= 0)
439: continue; /* Field nr 0, " " shouldn't be printed in this method. */
440:
441: snprintf(name, sizeof(name), "%s%s%s", " <%s>",
442: data_fields[j].format, "</%s>\n");
443:
444: /* XML doesn't allow "%" in tag names, rename Loss% to just Loss */
445: title = data_fields[j].title;
446: if (strcmp(data_fields[j].title, "Loss%") == 0) {
447: title = "Loss";
448: }
449:
1.1.1.3 ! misho 450: /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */
1.1 misho 451: if (strchr(data_fields[j].format, 'f')) {
452: printf(name,
453: title, data_fields[j].net_xxx(at) / 1000.0, title);
454: } else {
455: printf(name, title, data_fields[j].net_xxx(at), title);
456: }
457: }
458: printf(" </HUB>\n");
459: }
460: printf("</MTR>\n");
461: }
462:
463:
464: void csv_open(
465: void)
466: {
467: }
468:
469: void csv_close(
470: struct mtr_ctl *ctl,
471: time_t now)
472: {
1.1.1.3 ! misho 473: int i, j, at, max, z, w;
1.1 misho 474: ip_t *addr;
1.1.1.3 ! misho 475: ip_t *addr2 = NULL;
1.1 misho 476: char name[MAX_FORMAT_STR];
477:
478: for (i = 0; i < MAXFLD; i++) {
479: j = ctl->fld_index[ctl->fld_active[i]];
480: if (j < 0)
481: continue;
482: }
483:
484: max = net_max(ctl);
485: at = net_min(ctl);
486: for (; at < max; at++) {
487: addr = net_addr(at);
488: snprint_addr(ctl, name, sizeof(name), addr);
489:
490: if (at == net_min(ctl)) {
491: printf("Mtr_Version,Start_Time,Status,Host,Hop,Ip,");
492: #ifdef HAVE_IPINFO
493: if (!ctl->ipinfo_no) {
494: printf("Asn,");
495: }
496: #endif
497: for (i = 0; i < MAXFLD; i++) {
498: j = ctl->fld_index[ctl->fld_active[i]];
499: if (j < 0)
500: continue;
501: printf("%s,", data_fields[j].title);
502: }
503: printf("\n");
504: }
505: #ifdef HAVE_IPINFO
506: if (!ctl->ipinfo_no) {
507: char *fmtinfo = fmt_ipinfo(ctl, addr);
508: fmtinfo = trim(fmtinfo, '\0');
509: printf("MTR.%s,%lld,%s,%s,%d,%s,%s", PACKAGE_VERSION,
510: (long long) now, "OK", ctl->Hostname, at + 1, name,
511: fmtinfo);
512: } else
513: #endif
514: printf("MTR.%s,%lld,%s,%s,%d,%s", PACKAGE_VERSION,
515: (long long) now, "OK", ctl->Hostname, at + 1, name);
516:
517: for (i = 0; i < MAXFLD; i++) {
518: j = ctl->fld_index[ctl->fld_active[i]];
519: if (j < 0)
520: continue;
521:
1.1.1.3 ! misho 522: /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */
1.1 misho 523: if (strchr(data_fields[j].format, 'f')) {
524: printf(",%.2f",
525: (double) (data_fields[j].net_xxx(at) / 1000.0));
526: } else {
527: printf(",%d", data_fields[j].net_xxx(at));
528: }
529: }
530: printf("\n");
1.1.1.3 ! misho 531: if (ctl->reportwide == 0)
! 532: continue;
! 533:
! 534: for (z = 0; z < MAX_PATH; z++) {
! 535: int found = 0;
! 536: addr2 = net_addrs(at, z);
! 537: snprint_addr(ctl, name, sizeof(name), addr2);
! 538: if ((addrcmp
! 539: ((void *) &ctl->unspec_addr, (void *) addr2,
! 540: ctl->af)) == 0) {
! 541: break;
! 542: } else if ((addrcmp
! 543: ((void *) addr, (void *) addr2,
! 544: ctl->af)) == 0) {
! 545: continue; /* Latest Host is already printed */
! 546: } else {
! 547: for (w = 0; w < z; w++)
! 548: /* Ok... checking if there are ips repeated on same hop */
! 549: if ((addrcmp
! 550: ((void *) addr2, (void *) net_addrs(at, w),
! 551: ctl->af)) == 0) {
! 552: found = 1;
! 553: break;
! 554: }
! 555:
! 556: if (!found) {
! 557: #ifdef HAVE_IPINFO
! 558: if (!ctl->ipinfo_no) {
! 559: char *fmtinfo = fmt_ipinfo(ctl, addr2);
! 560: fmtinfo = trim(fmtinfo, '\0');
! 561: printf("MTR.%s,%lld,%s,%s,%d,%s,%s", PACKAGE_VERSION,
! 562: (long long) now, "OK", ctl->Hostname, at + 1, name,
! 563: fmtinfo);
! 564: } else
! 565: #endif
! 566: printf("MTR.%s,%lld,%s,%s,%d,%s", PACKAGE_VERSION,
! 567: (long long) now, "OK", ctl->Hostname, at + 1, name);
! 568:
! 569: /* Use values associated with the first ip discovered for this hop */
! 570: for (i = 0; i < MAXFLD; i++) {
! 571: j = ctl->fld_index[ctl->fld_active[i]];
! 572: if (j < 0)
! 573: continue;
! 574:
! 575: /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */
! 576: if (strchr(data_fields[j].format, 'f')) {
! 577: printf(",%.2f",
! 578: (double) (data_fields[j].net_xxx(at) / 1000.0));
! 579: } else {
! 580: printf(",%d", data_fields[j].net_xxx(at));
! 581: }
! 582: }
! 583: printf("\n");
! 584: }
! 585: }
! 586: }
1.1 misho 587: }
588: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>