Example #1
0
/**
 * return 0 on succes, <0 on fail (nothing sent), >0 on sent, but something
 * failed (do increment sent counter)
 */
static int
sendEcho(int fd, int seq)
{
	int err = 0;
        void *packet = 0;
        ssize_t packetlen;

	if (options.verbose > 2) {
		fprintf(stderr, "%s: sendEcho(%d, %d)\n", argv0, fd, seq);
	}

        if (0 > (packetlen = mkping(seq, &packet))) {
                err = packetlen;
                goto errout;
        }

	if (options.verbose > 1) {
		fprintf(stderr,	"%s: Sending GTP ping with seq=%d size %d\n",
			argv0, curSeq, (int)packetlen);
	}

        sendTimes[seq % TRACKPINGS_SIZE] = clock_get_dbl();
        gotIt[seq % TRACKPINGS_SIZE] = 0;

	if (packetlen != send(fd, packet, packetlen, 0)) {
		err = errno;
		if (err == ECONNREFUSED) {
                        printf("Connection refused\n");
                        connectionRefused++;
                        goto errout;
		}
                fprintf(stderr, "%s: send(%d, ...): %s\n",
                        argv0, fd, strerror(errno));
                err = -err;
                goto errout;
	}
 errout:
        free(packet);
	return 0;
}
Example #2
0
/**
 * return 0 on success/got reply,
 *        <0 on fail. Errno returned.
 *        >0 on success, but no packet (EINTR or dup packet)
 */
static int
recvEchoReply(int fd)
{
	int err;
        char packet[1024];
        ssize_t packetlen;
	double now;
	char lag[128];
        int isDup = 0;
        int isReorder = 0;
        int ttl;
        int tos;
        char tosString[128] = {0};
        char ttlString[128] = {0};
        struct GtpReply gtp;

	if (options.verbose > 2) {
		fprintf(stderr, "%s: recvEchoReply()\n", argv0);
	}

	now = clock_get_dbl();
	
	memset(packet, 0, sizeof(packet));
        if (0 > (packetlen = doRecv(fd,
                                    (void*)packet,
                                    sizeof(packet),
                                    &ttl,
                                    &tos))) {
		switch(errno) {
                case ECONNREFUSED:
                        connectionRefused++;
			handleRecvErr(fd, "Port closed", 0);
                        return 1;
		case EINTR:
                        return 1;
                case EHOSTUNREACH:
			handleRecvErr(fd, "Host unreachable or TTL exceeded",
                                      0);
                        return 1;
		default:
			err = errno;
			fprintf(stderr, "%s: recv(%d, ...): %s\n",
				argv0, fd, strerror(errno));
                        return err;
		}
	}

        /* create ttl string */
        if (0 <= ttl) {
                snprintf(ttlString, sizeof(ttlString), "ttl=%d ", ttl);
        }

        /* create tos string */
        if (0 <= tos) {
                char scratch[128];
                snprintf(tosString, sizeof(tosString),
                         "%s ", tos2String(tos,
                                           scratch,
                                           sizeof(scratch)));
        }

        gtp = parseReply(packet, packetlen);
        if (!gtp.ok) {
                return 1;
        }

	if (gtp.msg != GTPMSG_ECHOREPLY) {
		fprintf(stderr,
			"%s: Got non-EchoReply type of msg (type: %d)\n",
			argv0, gtp.msg);
                return 1;
	}

        if (curSeq - gtp.seq >= TRACKPINGS_SIZE) {
		strcpy(lag, "Inf");
	} else {
                int pos = gtp.seq % TRACKPINGS_SIZE;
                double lagf = now - sendTimes[pos];
                if (gotIt[pos]) {
                        isDup = 1;
                }
                gotIt[pos]++;
		snprintf(lag, sizeof(lag), "%.2f ms", 1000 * lagf);
                if (!isDup) {
                        totalTime += lagf;
                        totalTimeSquared += lagf * lagf;
                        totalTimeCount++;
                        if ((0 > totalMin) || (lagf < totalMin)) {
                                totalMin = lagf;
                        }
                        if ((0 > totalMax) || (lagf > totalMax)) {
                                totalMax = lagf;
                        }
                }
                if (options.autowait) {
                        options.wait = 2 * (totalTime / totalTimeCount);
                        if (options.verbose > 1) {
                                fprintf(stderr,
                                        "%s: Adjusting waittime to %.6f\n",
                                        argv0, options.wait);
                        }
                }
	}

        /* detect packet reordering */
        if (!isDup) {
                if (highestSeq > gtp.seq) {
                        reorder++;
                        isReorder = 1;
                } else {
                        highestSeq = gtp.seq;
                }
        }

        if (options.flood) {
                if (!isDup) {
                        printf("\b \b");
                }
        } else {
                printf("%u bytes from %s: ver=%d seq=%u %s%stime=%s%s%s\n",
                       (int)packetlen,
                       options.targetip,
                       gtp.version,
                       gtp.seq,
                       tosString[0] ? tosString : "",
                       ttlString[0] ? ttlString : "",
                       lag,
                       isDup ? " (DUP)" : "",
                       isReorder ? " (out of order)" : "");
        }
        if (isDup) {
                dups++;
        }
	return isDup;
}
Example #3
0
/**
 * FIXME: this function needs a cleanup, and probably some merging
 * with pingMainloop()
 */
static int
tracerouteMainloop(int fd)
{
        int ttl = 0;
        int ttlTry = 0;
        double curPingTime;
        double lastRecvTime = 0;
        double lastPingTime = 0;
        int n;
        int endOfTraceroute = 0;
        int printStar = 0;
        double timewait;

	printf("GTPING traceroute to %s (%s) packet version %d.\n",
	       options.target,
	       options.targetip,
	       (int)options.version);


	while (!sigintReceived) {
		struct pollfd fds;

		fds.fd = fd;
		fds.events = POLLIN;
		fds.revents = 0;
                
                /* time to send yet? */
		curPingTime = clock_get_dbl();
		if ((lastRecvTime >= lastPingTime)
                    || (curPingTime > lastPingTime + options.interval)) {
                        if (printStar) {
                                printf("*\n");
                        }
                        ttlTry++;
                        if (ttlTry < options.traceroutehops && ttl != 0) {
                                printf("     ");
                        } else {
                                if (endOfTraceroute) {
                                        break;
                                }
                                ttl++;
                                ttlTry = 0;
                                printf("%4d ", ttl);
                                fflush(stdout);
                        }
                        if (setsockopt(fd,
                                       SOL_IP,
                                       IP_TTL,
                                       &ttl,
                                       sizeof(ttl))) {
                                fprintf(stderr,
                                        "%s: setsockopt(%d, SOL_IP, IP_TTL, "
                                        "%d): %s\n", argv0, fd, ttl,
                                        strerror(errno));
                        }

                        if (0 <= sendEcho(fd, curSeq++)) {
                                lastPingTime = curPingTime;
                                printStar = 1;
                        }
                }

                /* max waittime: until it's time to send the next one */
		timewait = lastPingTime+options.interval - clock_get_dbl();
		if (timewait < 0) {
			timewait = 0;
		}
                timewait *= 0.5; /* leave room for overhead */

		switch ((n = poll(&fds, 1, (int)(timewait * 1000)))) {
		case 1: /* read ready */
                        printStar = 0;
			if (fds.revents & POLLERR) {
                                int e;
				e = handleRecvErr(fd, NULL, lastPingTime);
                                if (e) {
                                        lastRecvTime = clock_get_dbl();
                                }
                                if (e > 1) {
                                        endOfTraceroute = 1;
                                }
			}
			if (fds.revents & POLLIN) {
				n = recvEchoReply(fd);
                                endOfTraceroute = 1;
                                if (!n) {
                                        lastRecvTime = clock_get_dbl();
                                } else if (n > 0) {
                                        /* still ok, but no reply */
                                        printStar = 1;
                                } else {
                                        return 1;
                                }
			}
			break;
		case 0: /* timeout */
			break;
		case -1: /* error */
			switch (errno) {
			case EINTR:
			case EAGAIN:
				break;
			default:
				fprintf(stderr, "%s: poll([%d], 1, %d): %s\n",
					argv0,
					fd,
					(int)(timewait*1000),
					strerror(errno));
				exit(2);
			}
			break;
		default: /* can't happen */
			fprintf(stderr, "%s: poll() returned %d!\n", argv0, n);
			exit(2);
			break;
		}
        }
        return 0;
}
Example #4
0
/**
 * return value is sent directly to return value of main()
 */
static int
pingMainloop(int fd)
{
	unsigned sent = 0;
	unsigned recvd = 0;
	double lastpingTime = 0; /* last time we sent out a ping */
	double curPingTime;   /* if we ping now, this is the timestamp of it */
        double lastRecvTime = 0; /* last time we got a reply */
        int recvErrors = 0;

	if (options.verbose > 2) {
		fprintf(stderr, "%s: mainloop(%d)\n", argv0, fd);
	}

	startTime = clock_get_dbl();

	printf("GTPING %s (%s) packet version %d\n",
	       options.target,
	       options.targetip,
	       options.version);

        lastRecvTime = startTime;
	while (!sigintReceived) {
                /* max time to wait for replies before checking if it's time
                 * to send another ping */
		double timewait;
		int n;
		struct pollfd fds;

                /* sent all we are going to send, and got all replies
                 * (either errors or good replies)
                 */
                if (options.count
                    && (sent == options.count)
                    && (sent == (recvd + recvErrors))) {
                        break;
                }

                /* time to send yet? */
		curPingTime = clock_get_dbl();

                /* if clock is not monotonic and time set backwards
                 * since last ping, start a new ping cycle */
                if (curPingTime < lastpingTime) {
                        lastpingTime = curPingTime - options.interval - 0.001;
                }

		if (curPingTime > lastpingTime + options.interval) {
			if (options.count && (curSeq == options.count)) {
				if (lastRecvTime+options.wait < curPingTime) {
                                        break;
                                }
			} else if (0 <= sendEcho(fd, curSeq++)) {
                                sent++;
                                lastpingTime = curPingTime;
                                if (options.flood) {
                                        printf(".");
                                        fflush(stdout);
                                }
			}
		}

		fds.fd = fd;
		fds.events = POLLIN;
		fds.revents = 0;
		
                /* max waittime: until it's time to send the next one */
                timewait = lastpingTime+options.interval - clock_get_dbl();

                /* never wait more than an interval. this can happen if
                 * clock is not monotonic */
                if (timewait > options.interval) {
                        timewait = options.interval;
                }

                /* this should never happen, should have been taken care of
                 * above. */
		if (timewait < 0) {
			timewait = 0;
		}

                /* leave room for overhead */
                timewait *= 0.5;

		switch ((n = poll(&fds, 1, (int)(timewait * 1000)))) {
		case 1: /* read ready */
			if (fds.revents & POLLERR) {
                                if (handleRecvErr(fd, NULL, 0)) {
                                        recvErrors++;
                                }
			}
			if (fds.revents & POLLIN) {
				n = recvEchoReply(fd);
                                if (!n) {
                                        recvd++;
                                        lastRecvTime = clock_get_dbl();
                                } else if (n > 0) {
                                        /* still ok, but no reply */
                                } else { /* n < 0 */
                                        return 1;
                                }
			}
			break;
		case 0: /* timeout */
			break;
		case -1: /* error */
			switch (errno) {
			case EINTR:
			case EAGAIN:
				break;
			default:
				fprintf(stderr, "%s: poll([%d], 1, %d): %s\n",
					argv0,
					fd,
					(int)(timewait*1000),
					strerror(errno));
				exit(2);
			}
			break;
		default: /* can't happen */
			fprintf(stderr, "%s: poll() returned %d!\n", argv0, n);
			exit(2);
			break;
		}
			
	}
	printf("\n--- %s GTP ping statistics ---\n"
               "%u packets transmitted, %u received, "
               "%d%% packet loss, "
               "time %dms\n"
               "%u out of order, %u dups, "
               "%u connection refused",
	       options.target,
               sent, recvd,
	       (int)((100.0*(sent-recvd))/sent),
               (int)(1000*(clock_get_dbl()-startTime)),
               reorder, dups,
               connectionRefused);
        errInspectionPrintSummary();
        printf("\n");
	if (totalTimeCount) {
		printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f ms",
		       1000*totalMin,
		       1000*(totalTime / totalTimeCount),
		       1000*totalMax,
		       1000*sqrt((totalTimeSquared -
				  (totalTime * totalTime)
				  /totalTimeCount)/totalTimeCount));
	}
	printf("\n");
	return recvd == 0;
}
Example #5
0
/**
 * return:
 *      0 if no error
 *      1 if TTL exceeded
 *     >1 if other icmp-like error
 */
static int
handleRecvErrSEE(struct sock_extended_err *see,
                 int returnttl,
                 const char *tos,
                 double lastPingTime)
{
	int isicmp = 0;
        int ret = 0;

	if (!see) {
		fprintf(stderr, "%s: Error, but no error info\n", argv0);
		return ret;
	}

	/* print "From ...: */
        if (see->ee_origin == SO_EE_ORIGIN_LOCAL) {
		printf("From local system: ");
	} else {
		struct sockaddr *offender = SO_EE_OFFENDER(see);
		char abuf[NI_MAXHOST];
		int err;
		
		if (offender->sa_family == AF_UNSPEC) {
                        if (!options.traceroute) { printf("From "); }
                        printf("<unknown>: ");
		} else if ((err = getnameinfo(offender,
					      sizeof(struct sockaddr_storage),
					      abuf, NI_MAXHOST,
					      NULL, 0,
					      NI_NUMERICHOST))) {
			fprintf(stderr, "%s: getnameinfo(): %s\n",
				argv0, gai_strerror(err));
                        if (!options.traceroute) { printf("From "); }
                        printf("<unknown>");
                        if (tos) {
                                printf(" %s", tos);
                        }
                        if (returnttl > 0) {
                                printf(" ttl=%d", returnttl);
                        }
                        printf(": ");
		} else {
                        if (!options.traceroute) { printf("From "); }
                        printf("%s", abuf);
                        if (tos) {
                                printf(" %s", tos);
                        }
                        if (returnttl > 0) {
                                printf(" ttl=%d", returnttl);
                        }
                        if (lastPingTime) {
                                printf(" time=%.2f ms",
                                       1000*(clock_get_dbl()-lastPingTime));
                        }
                        printf(": ");
		}
	}
	
	if (see->ee_origin == SO_EE_ORIGIN_ICMP6
	    || see->ee_origin == SO_EE_ORIGIN_ICMP) {
		isicmp = 1;
	}

	/* Print error message */
	switch (see->ee_errno) {
	case ECONNREFUSED:
		printf("Port closed");
                ret = 2;
		break;
	case EMSGSIZE:
		printf("PMTU %d", see->ee_info);
                ret = 2;
		break;
	case EPROTO:
		printf("Protocol error");
                ret = 2;
		break;
	case ENETUNREACH:
		printf("Network unreachable");
                ret = 2;
		break;
	case EACCES:
		printf("Access denied");
                ret = 2;
		break;
	case EHOSTUNREACH:
		if (isicmp && see->ee_type == 11 && see->ee_code == 0) {
                        printf("TTL exceeded");
                        ret = 1;
                } else {
			printf("Host unreachable");
                        ret = 2;
		}
		break;
	default:
		printf("%s", strerror(see->ee_errno));
                ret = 2;
		break;
	}
        icmpError++;
	if (options.verbose && (0 < returnttl)) {
		printf(". return TTL: %d.", returnttl);
	}
	printf("\n");
        return ret;
}