Annotation of embedaddon/mtr/ui/net.c, revision 1.1.1.2
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 <errno.h>
1.1.1.2 ! misho 22: #include <sys/types.h>
! 23: #include <ifaddrs.h>
1.1 misho 24: #include <math.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/select.h>
28: #include <unistd.h>
29:
30: #ifdef HAVE_ERROR_H
31: #include <error.h>
32: #else
33: #include "portability/error.h"
34: #endif
35:
36: #include "mtr.h"
37: #include "cmdpipe.h"
38: #include "net.h"
39: #include "display.h"
40: #include "dns.h"
41: #include "utils.h"
1.1.1.2 ! misho 42: #include "packet/sockaddr.h"
1.1 misho 43:
44: #define MinSequence 33000
45: #define MaxSequence 65536
46:
47: static int packetsize; /* packet size used by ping */
48:
49: struct nethost {
1.1.1.2 ! misho 50: ip_t addr; /* Latest host to respond */
! 51: ip_t addrs[MAX_PATH]; /* For Multi paths/Path Changes: List of all hosts that have responded */
! 52: int err;
1.1 misho 53: int xmit;
54: int returned;
55: int sent;
56: int up;
57: long long ssd; /* sum of squares of differences from the current average */
58: int last;
59: int best;
60: int worst;
61: int avg; /* average: addByMin */
62: int gmean; /* geometric mean: addByMin */
63: int jitter; /* current jitter, defined as t1-t0 addByMin */
64: int javg; /* avg jitter */
65: int jworst; /* max jitter */
66: int jinta; /* estimated variance,? rfc1889's "Interarrival Jitter" */
67: int transit;
68: int saved[SAVED_PINGS];
69: int saved_seq_offset;
70: struct mplslen mpls;
1.1.1.2 ! misho 71: struct mplslen mplss[MAX_PATH];
1.1 misho 72: };
73:
74:
75: struct sequence {
76: int index;
77: int transit;
78: int saved_seq;
79: struct timeval time;
80: };
81:
82:
83: static struct nethost host[MaxHost];
84: static struct sequence sequence[MaxSequence];
85: static struct packet_command_pipe_t packet_command_pipe;
86:
87: static struct sockaddr_storage sourcesockaddr_struct;
88: static struct sockaddr_storage remotesockaddr_struct;
89:
90: static struct sockaddr *sourcesockaddr =
91: (struct sockaddr *) &sourcesockaddr_struct;
92: static struct sockaddr *remotesockaddr =
93: (struct sockaddr *) &remotesockaddr_struct;
94:
95: static ip_t *sourceaddress;
96: static ip_t *remoteaddress;
97:
98: #ifdef ENABLE_IPV6
99: static char localaddr[INET6_ADDRSTRLEN];
100: #else
101: #ifndef INET_ADDRSTRLEN
102: #define INET_ADDRSTRLEN 16
103: #endif
104: static char localaddr[INET_ADDRSTRLEN];
105: #endif
106:
107: static int batch_at = 0;
108: static int numhosts = 10;
109:
1.1.1.2 ! misho 110:
! 111: #define host_addr_cmp(index, other, af) \
! 112: addrcmp((void *) &(host[(index)].addr), (void *) (other), (af))
! 113:
! 114: #define host_addrs_cmp(index, path, other, af) \
! 115: addrcmp((void *) &(host[(index)].addrs[path]), (void *) (other), (af))
! 116:
! 117:
1.1 misho 118: /* return the number of microseconds to wait before sending the next
119: ping */
120: int calc_deltatime(
121: float waittime)
122: {
123: waittime /= numhosts;
124: return 1000000 * waittime;
125: }
126:
127:
128: static void save_sequence(
129: struct mtr_ctl *ctl,
130: int index,
131: int seq)
132: {
133: display_rawxmit(ctl, index, seq);
134:
135: sequence[seq].index = index;
136: sequence[seq].transit = 1;
137: sequence[seq].saved_seq = ++host[index].xmit;
138: memset(&sequence[seq].time, 0, sizeof(sequence[seq].time));
139:
140: host[index].transit = 1;
141:
142: if (host[index].sent) {
143: host[index].up = 0;
144: }
145:
146: host[index].sent = 1;
147: net_save_xmit(index);
148: }
149:
150: static int new_sequence(
151: struct mtr_ctl *ctl,
152: int index)
153: {
154: static int next_sequence = MinSequence;
155: int seq;
156:
157: seq = next_sequence++;
158: if (next_sequence >= MaxSequence) {
159: next_sequence = MinSequence;
160: }
161:
162: save_sequence(ctl, index, seq);
163:
164: return seq;
165: }
166:
167:
168: /* Attempt to find the host at a particular number of hops away */
169: static void net_send_query(
170: struct mtr_ctl *ctl,
171: int index,
172: int packet_size)
173: {
174: int seq = new_sequence(ctl, index);
175: int time_to_live = index + 1;
176:
177: send_probe_command(ctl, &packet_command_pipe, remoteaddress,
1.1.1.2 ! misho 178: sourceaddress, packet_size, seq, time_to_live);
1.1 misho 179: }
180:
181:
1.1.1.2 ! misho 182: /*
! 183: Mark a sequence entry as completed and return the host index
! 184: being probed.
! 185:
! 186: Returns -1 in the case of an invalid sequence number.
! 187: */
! 188: static int mark_sequence_complete(
! 189: int seq)
! 190: {
! 191: if ((seq < 0) || (seq >= MaxSequence)) {
! 192: return -1;
! 193: }
! 194:
! 195: if (!sequence[seq].transit) {
! 196: return -1;
! 197: }
! 198: sequence[seq].transit = 0;
! 199:
! 200: return sequence[seq].index;
! 201: }
! 202:
! 203:
! 204: /*
! 205: A probe has successfully completed.
! 206:
! 207: Record the round trip time and address of the responding host.
! 208: */
! 209:
1.1 misho 210: static void net_process_ping(
211: struct mtr_ctl *ctl,
212: int seq,
1.1.1.2 ! misho 213: int err,
1.1 misho 214: struct mplslen *mpls,
215: ip_t * addr,
216: int totusec)
217: {
218: int index;
219: int oldavg; /* usedByMin */
220: int oldjavg; /* usedByMin */
221: int i; /* usedByMin */
1.1.1.2 ! misho 222: int found = 0;
1.1 misho 223: #ifdef ENABLE_IPV6
224: char addrcopy[sizeof(struct in6_addr)];
225: #else
226: char addrcopy[sizeof(struct in_addr)];
227: #endif
1.1.1.2 ! misho 228: struct nethost *nh = NULL;
1.1 misho 229:
1.1.1.2 ! misho 230: memcpy(&addrcopy, addr, sockaddr_addr_size(sourcesockaddr));
1.1 misho 231:
1.1.1.2 ! misho 232: index = mark_sequence_complete(seq);
! 233: if (index < 0) {
1.1 misho 234: return;
235: }
1.1.1.2 ! misho 236: nh = &host[index];
! 237: nh->err = err;
1.1 misho 238:
239:
240:
1.1.1.2 ! misho 241: if (addrcmp(&nh->addr, &addrcopy, ctl->af) != 0) {
! 242: for (i = 0; i < MAX_PATH;) {
! 243: if (addrcmp(&nh->addrs[i], &nh->addr, ctl->af) == 0) {
! 244: found = 1; /* This host is already in the list */
1.1 misho 245: break;
246: }
1.1.1.2 ! misho 247: if (addrcmp(&nh->addrs[i], &ctl->unspec_addr, ctl->af) == 0) {
! 248: break; /* Found first vacant position */
! 249: }
1.1 misho 250: i++;
251: }
252:
1.1.1.2 ! misho 253: if (found == 0 && i < MAX_PATH) {
! 254: memcpy(&nh->addrs[i], &nh->addr, sockaddr_addr_size(sourcesockaddr));
! 255:
! 256: nh->mplss[i] = nh->mpls;
! 257: display_rawhost(ctl, index, (void *)&(nh->addrs[i]), (void *)&(nh->addrs[i]));
1.1 misho 258: }
1.1.1.2 ! misho 259:
! 260: /* Always save the latest host in nh->addr. This
! 261: * allows maxTTL to change whenever path changes.
! 262: */
! 263: memcpy(&nh->addr, addrcopy, sockaddr_addr_size(sourcesockaddr));
! 264: nh->mpls = *mpls;
! 265: display_rawhost(ctl, index, (void *)&(nh->addr), (void *)&(nh->mpls));
1.1 misho 266: }
267:
1.1.1.2 ! misho 268: nh->jitter = totusec - nh->last;
! 269: if (nh->jitter < 0) {
! 270: nh->jitter = -nh->jitter;
1.1 misho 271: }
272:
1.1.1.2 ! misho 273: nh->last = totusec;
1.1 misho 274:
1.1.1.2 ! misho 275: if (nh->returned < 1) {
! 276: nh->best = nh->worst = nh->gmean = totusec;
! 277: nh->avg = nh->ssd = 0;
1.1 misho 278:
1.1.1.2 ! misho 279: nh->jitter = nh->jworst = nh->jinta = 0;
1.1 misho 280: }
281:
1.1.1.2 ! misho 282: if (totusec < nh->best) {
! 283: nh->best = totusec;
1.1 misho 284: }
1.1.1.2 ! misho 285: if (totusec > nh->worst) {
! 286: nh->worst = totusec;
1.1 misho 287: }
288:
1.1.1.2 ! misho 289: if (nh->jitter > nh->jworst) {
! 290: nh->jworst = nh->jitter;
1.1 misho 291: }
292:
1.1.1.2 ! misho 293: nh->returned++;
! 294: oldavg = nh->avg;
! 295: nh->avg += (totusec - oldavg + .0) / nh->returned;
! 296: nh->ssd +=
! 297: (totusec - oldavg + .0) * (totusec - nh->avg);
1.1 misho 298:
1.1.1.2 ! misho 299: oldjavg = nh->javg;
! 300: nh->javg +=
! 301: (nh->jitter - oldjavg) / nh->returned;
1.1 misho 302: /* below algorithm is from rfc1889, A.8 */
1.1.1.2 ! misho 303: nh->jinta +=
! 304: nh->jitter - ((nh->jinta + 8) >> 4);
1.1 misho 305:
1.1.1.2 ! misho 306: if (nh->returned > 1) {
! 307: nh->gmean =
! 308: pow((double) nh->gmean,
! 309: (nh->returned - 1.0) / nh->returned)
! 310: * pow((double) totusec, 1.0 / nh->returned);
1.1 misho 311: }
312:
1.1.1.2 ! misho 313: nh->sent = 0;
! 314: nh->up = 1;
! 315: nh->transit = 0;
1.1 misho 316:
317: net_save_return(index, sequence[seq].saved_seq, totusec);
318: display_rawping(ctl, index, totusec, seq);
319: }
320:
321: /*
322: Invoked when the read pipe from the mtr-packet subprocess is readable.
323: If we have received a complete reply, process it.
324: */
325: void net_process_return(
326: struct mtr_ctl *ctl)
327: {
328: handle_command_replies(ctl, &packet_command_pipe, net_process_ping);
329: }
330:
331:
332: ip_t *net_addr(
333: int at)
334: {
335: return (ip_t *) & (host[at].addr);
336: }
337:
338:
339: ip_t *net_addrs(
340: int at,
341: int i)
342: {
343: return (ip_t *) & (host[at].addrs[i]);
344: }
345:
1.1.1.2 ! misho 346: /*
! 347: Get the error code corresponding to a host entry.
! 348: */
! 349: int net_err(
! 350: int at)
! 351: {
! 352: return host[at].err;
! 353: }
! 354:
1.1 misho 355: void *net_mpls(
356: int at)
357: {
358: return (struct mplslen *) &(host[at].mplss);
359: }
360:
361: void *net_mplss(
362: int at,
363: int i)
364: {
365: return (struct mplslen *) &(host[at].mplss[i]);
366: }
367:
368: int net_loss(
369: int at)
370: {
371: if ((host[at].xmit - host[at].transit) == 0) {
372: return 0;
373: }
374:
375: /* times extra 1000 */
376: return 1000 * (100 -
377: (100.0 * host[at].returned /
378: (host[at].xmit - host[at].transit)));
379: }
380:
381:
382: int net_drop(
383: int at)
384: {
385: return (host[at].xmit - host[at].transit) - host[at].returned;
386: }
387:
388:
389: int net_last(
390: int at)
391: {
392: return (host[at].last);
393: }
394:
395:
396: int net_best(
397: int at)
398: {
399: return (host[at].best);
400: }
401:
402:
403: int net_worst(
404: int at)
405: {
406: return (host[at].worst);
407: }
408:
409:
410: int net_avg(
411: int at)
412: {
413: return (host[at].avg);
414: }
415:
416:
417: int net_gmean(
418: int at)
419: {
420: return (host[at].gmean);
421: }
422:
423:
424: int net_stdev(
425: int at)
426: {
427: if (host[at].returned > 1) {
428: return (sqrt(host[at].ssd / (host[at].returned - 1.0)));
429: } else {
430: return (0);
431: }
432: }
433:
434:
435: int net_jitter(
436: int at)
437: {
438: return (host[at].jitter);
439: }
440:
441:
442: int net_jworst(
443: int at)
444: {
445: return (host[at].jworst);
446: }
447:
448:
449: int net_javg(
450: int at)
451: {
452: return (host[at].javg);
453: }
454:
455:
456: int net_jinta(
457: int at)
458: {
459: return (host[at].jinta);
460: }
461:
462:
463: int net_max(
464: struct mtr_ctl *ctl)
465: {
466: int at;
467: int max;
468:
469: max = 0;
1.1.1.2 ! misho 470: for (at = 0; at < ctl->maxTTL; at++) {
! 471: if (host_addr_cmp(at , remoteaddress, ctl->af) == 0) {
1.1 misho 472: return at + 1;
1.1.1.2 ! misho 473: } else if (host[at].err != 0) {
! 474: /*
! 475: If a hop has returned an ICMP error
! 476: (such as "no route to host") then we'll consider that the
! 477: final hop.
! 478: */
! 479: return at + 1;
! 480: } else if (host_addr_cmp(at, &ctl->unspec_addr, ctl->af) != 0) {
1.1 misho 481: max = at + 2;
482: }
483: }
484:
1.1.1.2 ! misho 485: if (max > ctl->maxTTL)
! 486: max = ctl->maxTTL;
1.1 misho 487: return max;
488: }
489:
490:
491: int net_min(
492: struct mtr_ctl *ctl)
493: {
494: return (ctl->fstTTL - 1);
495: }
496:
497:
498: int net_returned(
499: int at)
500: {
501: return host[at].returned;
502: }
503:
504:
505: int net_xmit(
506: int at)
507: {
508: return host[at].xmit;
509: }
510:
511:
512: int net_up(
513: int at)
514: {
515: return host[at].up;
516: }
517:
518:
519: char *net_localaddr(
520: void)
521: {
522: return localaddr;
523: }
524:
525:
526: void net_end_transit(
527: void)
528: {
529: int at;
530:
531: for (at = 0; at < MaxHost; at++) {
532: host[at].transit = 0;
533: }
534: }
535:
536: int net_send_batch(
537: struct mtr_ctl *ctl)
538: {
539: int n_unknown = 0, i;
1.1.1.2 ! misho 540: int restart = 0;
1.1 misho 541:
542: /* randomized packet size and/or bit pattern if packetsize<0 and/or
543: bitpattern<0. abs(packetsize) and/or abs(bitpattern) will be used
544: */
545: if (batch_at < ctl->fstTTL) {
546: if (ctl->cpacketsize < 0) {
547: /* Someone used a formula here that tried to correct for the
548: "end-error" in "rand()". By "end-error" I mean that if you
549: have a range for "rand()" that runs to 32768, and the
550: destination range is 10000, you end up with 4 out of 32768
551: 0-2768's and only 3 out of 32768 for results 2769 .. 9999.
1.1.1.2 ! misho 552: As our destination range (in the example 10000) is much
1.1 misho 553: smaller (reasonable packet sizes), and our rand() range much
554: larger, this effect is insignificant. Oh! That other formula
555: didn't work. */
556: packetsize =
557: MINPACKET + rand() % (-ctl->cpacketsize - MINPACKET);
558: } else {
559: packetsize = ctl->cpacketsize;
560: }
561: if (ctl->bitpattern < 0) {
562: ctl->bitpattern =
563: -(int) (256 + 255 * (rand() / (RAND_MAX + 0.1)));
564: }
565: }
566:
567: net_send_query(ctl, batch_at, abs(packetsize));
568:
569: for (i = ctl->fstTTL - 1; i < batch_at; i++) {
1.1.1.2 ! misho 570: if (host_addr_cmp(i, &ctl->unspec_addr, ctl->af) == 0)
1.1 misho 571: n_unknown++;
572:
573: /* The second condition in the next "if" statement was added in mtr-0.56,
574: but I don't remember why. It makes mtr stop skipping sections of unknown
575: hosts. Removed in 0.65.
576: If the line proves necessary, it should at least NOT trigger that line
577: when host[i].addr == 0 */
1.1.1.2 ! misho 578: if (host_addr_cmp(i, remoteaddress, ctl->af) == 0) {
! 579: restart = 1;
! 580: numhosts = i + 1; /* Saves batch_at - index number of probes in the next round!*/
! 581: break;
! 582: }
1.1 misho 583: }
584:
585: if ( /* success in reaching target */
1.1.1.2 ! misho 586: (host_addr_cmp(batch_at, remoteaddress, ctl->af) == 0) ||
1.1 misho 587: /* fail in consecutive maxUnknown (firewall?) */
588: (n_unknown > ctl->maxUnknown) ||
589: /* or reach limit */
590: (batch_at >= ctl->maxTTL - 1)) {
1.1.1.2 ! misho 591: restart = 1;
1.1 misho 592: numhosts = batch_at + 1;
1.1.1.2 ! misho 593: }
! 594:
! 595: if(restart) {
1.1 misho 596: batch_at = ctl->fstTTL - 1;
597: return 1;
598: }
599:
600: batch_at++;
601: return 0;
602: }
603:
604:
605: /* Ensure the interface address a valid address for our use */
606: static void net_validate_interface_address(
607: int address_family,
608: char *interface_address)
609: {
610: if (inet_pton(address_family, interface_address, sourceaddress) != 1) {
611: error(EXIT_FAILURE, errno, "invalid local address");
612: }
613:
614: if (inet_ntop
615: (address_family, sourceaddress, localaddr,
616: sizeof(localaddr)) == NULL) {
617: error(EXIT_FAILURE, errno, "invalid local address");
618: }
619: }
620:
621:
622: /*
1.1.1.2 ! misho 623: Given the name of a network interface and a preferred address
! 624: family (IPv4 or IPv6), find the source IP address for sending
! 625: probes from that interface.
! 626: */
! 627: static void net_find_interface_address_from_name(
! 628: struct sockaddr_storage *addr,
! 629: int address_family,
! 630: const char *interface_name)
! 631: {
! 632: struct ifaddrs *ifaddrs;
! 633: struct ifaddrs *interface;
! 634: int found_interface_name = 0;
! 635:
! 636: if (getifaddrs(&ifaddrs) != 0) {
! 637: error(EXIT_FAILURE, errno, "getifaddrs failure");
! 638: }
! 639:
! 640: interface = ifaddrs;
! 641: while (interface != NULL) {
! 642: if (interface->ifa_addr != NULL && !strcmp(interface->ifa_name, interface_name)) {
! 643: found_interface_name = 1;
! 644:
! 645: if (interface->ifa_addr->sa_family == address_family) {
! 646: if (address_family == AF_INET) {
! 647: memcpy(addr,
! 648: interface->ifa_addr, sizeof(struct sockaddr_in));
! 649: freeifaddrs(ifaddrs);
! 650:
! 651: return;
! 652: } else if (address_family == AF_INET6) {
! 653: memcpy(addr,
! 654: interface->ifa_addr, sizeof(struct sockaddr_in6));
! 655: freeifaddrs(ifaddrs);
! 656:
! 657: return;
! 658: }
! 659: }
! 660: }
! 661:
! 662: interface = interface->ifa_next;
! 663: }
! 664:
! 665: if (!found_interface_name) {
! 666: error(EXIT_FAILURE, 0, "no such interface");
! 667: } else if (address_family == AF_INET) {
! 668: error(EXIT_FAILURE, 0, "interface missing IPv4 address");
! 669: } else if (address_family == AF_INET6) {
! 670: error(EXIT_FAILURE, 0, "interface missing IPv6 address");
! 671: } else {
! 672: error(EXIT_FAILURE, 0, "interface missing address");
! 673: }
! 674: }
! 675:
! 676:
! 677: /*
1.1 misho 678: Find the local address we will use to sent to the remote
679: host by connecting a UDP socket and checking the address
680: the socket is bound to.
681: */
682: static void net_find_local_address(
683: void)
684: {
685: int udp_socket;
686: int addr_length;
687: struct sockaddr_storage remote_sockaddr;
688:
689: udp_socket =
690: socket(remotesockaddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
691: if (udp_socket == -1) {
692: error(EXIT_FAILURE, errno, "udp socket creation failed");
693: }
694:
695: /*
696: We need to set the port to a non-zero value for the connect
697: to succeed.
698: */
1.1.1.2 ! misho 699: addr_length = sockaddr_size(&remotesockaddr_struct);
! 700: memcpy(&remote_sockaddr, &remotesockaddr_struct, addr_length);
! 701: *sockaddr_port_offset(&remote_sockaddr) = htons(1);
1.1 misho 702:
703: if (connect
1.1.1.2 ! misho 704: (udp_socket, (struct sockaddr *) &remote_sockaddr, sockaddr_size(&remote_sockaddr))) {
! 705: #ifdef __linux__
! 706: /* Linux doesn't require source address, so we can support
! 707: * a case when mtr is run against unreachable host (that can become
! 708: * reachable) */
! 709: if (errno == EHOSTUNREACH) {
! 710: close(udp_socket);
! 711: localaddr[0] = '\0';
! 712: return;
! 713: }
! 714: #endif
1.1 misho 715: error(EXIT_FAILURE, errno, "udp socket connect failed");
716: }
717:
718: if (getsockname(udp_socket, sourcesockaddr, &addr_length)) {
719:
720: error(EXIT_FAILURE, errno, "local address determination failed");
721: }
722:
1.1.1.2 ! misho 723: inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr));
1.1 misho 724:
725: close(udp_socket);
726: }
727:
728:
729: int net_open(
730: struct mtr_ctl *ctl,
731: struct hostent *hostent)
732: {
733: int err;
734:
735: /* Spawn the mtr-packet child process */
736: err = open_command_pipe(ctl, &packet_command_pipe);
737: if (err) {
738: return err;
739: }
740:
741: net_reset(ctl);
742:
1.1.1.2 ! misho 743: remotesockaddr->sa_family = sourcesockaddr->sa_family = hostent->h_addrtype;
! 744: memcpy(sockaddr_addr_offset(remotesockaddr), hostent->h_addr, sockaddr_addr_size(remotesockaddr));
1.1 misho 745:
1.1.1.2 ! misho 746: sourceaddress = sockaddr_addr_offset(sourcesockaddr);
! 747: remoteaddress = sockaddr_addr_offset(remotesockaddr);
1.1 misho 748:
749: if (ctl->InterfaceAddress) {
750: net_validate_interface_address(ctl->af, ctl->InterfaceAddress);
1.1.1.2 ! misho 751: } else if (ctl->InterfaceName) {
! 752: net_find_interface_address_from_name(
! 753: &sourcesockaddr_struct, ctl->af, ctl->InterfaceName);
! 754: inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr));
1.1 misho 755: } else {
756: net_find_local_address();
757: }
758:
759: return 0;
760: }
761:
762:
763: void net_reopen(
764: struct mtr_ctl *ctl,
765: struct hostent *addr)
766: {
767: int at;
768:
769: for (at = 0; at < MaxHost; at++) {
770: memset(&host[at], 0, sizeof(host[at]));
771: }
772:
773: remotesockaddr->sa_family = addr->h_addrtype;
1.1.1.2 ! misho 774: memcpy(remoteaddress, addr->h_addr, sockaddr_addr_size(remotesockaddr));
! 775: memcpy(sockaddr_addr_offset(remotesockaddr), addr->h_addr, sockaddr_addr_size(remotesockaddr));
1.1 misho 776: net_reset(ctl);
777: net_send_batch(ctl);
778: }
779:
780:
781: void net_reset(
782: struct mtr_ctl *ctl)
783: {
784: static struct nethost template = {
785: .saved_seq_offset = 2 - SAVED_PINGS
786: };
787:
788: int at, i;
789:
790: batch_at = ctl->fstTTL - 1; /* above replacedByMin */
791: numhosts = 10;
792:
793: for (i = 0; i < SAVED_PINGS; i++)
794: template.saved[i] = -2;
795:
796: for (at = 0; at < MaxHost; at++) {
797: memcpy(&(host[at]), &template, sizeof(template));
798: }
799:
800: for (at = 0; at < MaxSequence; at++) {
801: sequence[at].transit = 0;
802: }
803:
804: }
805:
806:
807: /* Close the pipe to the packet generator process, and kill the process */
808: void net_close(
809: void)
810: {
811: close_command_pipe(&packet_command_pipe);
812: }
813:
814:
815: int net_waitfd(
816: void)
817: {
818: return packet_command_pipe.read_fd;
819: }
820:
821:
822: int *net_saved_pings(
823: int at)
824: {
825: return host[at].saved;
826: }
827:
828:
829: static void net_save_increment(
830: void)
831: {
832: int at;
833: for (at = 0; at < MaxHost; at++) {
834: memmove(host[at].saved, host[at].saved + 1,
835: (SAVED_PINGS - 1) * sizeof(int));
836: host[at].saved[SAVED_PINGS - 1] = -2;
837: host[at].saved_seq_offset += 1;
838: }
839: }
840:
841:
842: void net_save_xmit(
843: int at)
844: {
845: if (host[at].saved[SAVED_PINGS - 1] != -2)
846: net_save_increment();
847: host[at].saved[SAVED_PINGS - 1] = -1;
848: }
849:
850:
851: void net_save_return(
852: int at,
853: int seq,
854: int ms)
855: {
856: int idx;
857: idx = seq - host[at].saved_seq_offset;
858: if ((idx < 0) || (idx >= SAVED_PINGS)) {
859: return;
860: }
861: host[at].saved[idx] = ms;
862: }
863:
864: /* Address comparison. */
865: int addrcmp(
1.1.1.2 ! misho 866: void *a,
! 867: void *b,
1.1 misho 868: int family)
869: {
870: int rc = -1;
871:
872: switch (family) {
873: case AF_INET:
874: rc = memcmp(a, b, sizeof(struct in_addr));
875: break;
876: #ifdef ENABLE_IPV6
877: case AF_INET6:
878: rc = memcmp(a, b, sizeof(struct in6_addr));
879: break;
880: #endif
881: }
882:
883: return rc;
884: }
885:
886: /* for GTK frontend */
887: void net_harvest_fds(
888: struct mtr_ctl *ctl)
889: {
890: fd_set writefd;
891: int maxfd = 0;
892: struct timeval tv;
893:
894: FD_ZERO(&writefd);
895: tv.tv_sec = 0;
896: tv.tv_usec = 0;
897: select(maxfd, NULL, &writefd, NULL, &tv);
898: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>