head 1.11; access; symbols; locks; strict; comment @ * @; 1.11 date 2006.04.19.23.23.48; author wessels; state Exp; branches; next 1.10; 1.10 date 2006.04.19.23.22.45; author wessels; state Exp; branches; next 1.9; 1.9 date 2002.01.31.04.56.11; author wessels; state Exp; branches; next 1.8; 1.8 date 2000.10.07.16.25.50; author wessels; state Exp; branches; next 1.7; 1.7 date 97.08.16.03.19.01; author wessels; state Exp; branches; next 1.6; 1.6 date 97.08.16.03.18.37; author wessels; state Exp; branches; next 1.5; 1.5 date 97.08.15.05.29.22; author wessels; state Exp; branches; next 1.4; 1.4 date 97.08.15.05.10.11; author wessels; state Exp; branches; next 1.3; 1.3 date 97.08.15.05.09.53; author wessels; state Exp; branches; next 1.2; 1.2 date 97.07.08.00.09.41; author wessels; state Exp; branches; next 1.1; 1.1 date 97.07.08.00.08.55; author wessels; state Exp; branches; next ; desc @@ 1.11 log @indent @ text @/* * $Id: mping.c,v 1.10 2006/04/19 23:22:45 wessels Exp wessels $ * * Copyright Duane Wessels * * To compile: * * % cc mping.c -o mping -lcurses */ #include #include #include #include extern int errno; #include #include char *strchr(); char *strrchr(); #include #include #include #if defined(__sgi__) #include #endif #if !defined(__sgi__) && !defined(__sun__) && !defined(__linux__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #define MAX_PKT_SZ 4096 #define DEF_PKT_SZ 64 #define HIST_SIZE 200 #define SIZE_ICMP_HDR 8 #define SIZE_TIME_DATA 8 #define DEF_DATALEN 56 #define DEF_NPKTS 10 #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif static unsigned char send_pkt[MAX_PKT_SZ]; static unsigned char recv_pkt[MAX_PKT_SZ]; static struct sockaddr_in from_addr; static int icmp_sock; static int datalen; static int ident; static int icmp_pktsize; static int delay; /* milliseconds */ static struct protoent *proto; static char *progname; static struct timeval now_tv; typedef struct _site { char to_host[256]; struct sockaddr_in to_addr; int rtt_hist[HIST_SIZE]; int ttl_hist[HIST_SIZE]; int high_seq; int npkts_sent; int nrecv; /* total # pings sent */ int ttl; double rtt; double avrtt; struct timeval last_sent; } site_t; #define MAX_N_SITES 100 static site_t Sites[MAX_N_SITES]; static int NSites; int main(int argc, char **argv); void create_windows(void); int in_cksum(unsigned short *ptr, int size); void main_loop(void); int recv_ping(void); void send_next_ping(void); time_t send_ping(site_t *); int tvsub(struct timeval *t1, struct timeval *t2); static WINDOW *w; static void do_stats(void) { int i; int j; int nloss = 0; int nsent = 0; int pct_loss = 0; char buf[128]; int rtt; int min = 5000, max = 0, avg = 0, sum = 0, count = 0; time_t now = time(NULL); int xtracols; site_t *S = NULL; int ttl_min; int ttl_max; int ttl; move(0, 0); for (i = 0; i < NSites; i++) { S = &Sites[i]; nloss = 0; pct_loss = 0; nsent = 0; min = 5000; max = 0; avg = 0; sum = 0; count = 0; ttl_min = 255; ttl_max = 0; for (j = 0; j < HIST_SIZE; j++) { rtt = S->rtt_hist[j]; if (rtt < 0) continue; nsent++; if (rtt == 0) { nloss++; continue; } if (rtt < min) min = rtt; if (rtt > max) max = rtt; sum += rtt; ttl = S->ttl_hist[j]; if (0 < ttl && ttl < ttl_min) ttl_min = ttl; if (ttl > ttl_max) ttl_max = ttl; count++; } if (nsent) pct_loss = 100 * nloss / nsent; if (count) avg = sum / count; sprintf(buf, "%-23.23s %d/%d/%d, %dms, %d%% loss", S->to_host, min, avg, max, (int)(S->avrtt + 0.5), /* ttl_min, S->ttl, ttl_max, */ pct_loss); printw("%-57.57s", buf); xtracols = w->_maxx - 58; assert(xtracols < HIST_SIZE); for (j = (HIST_SIZE - xtracols); j < HIST_SIZE; j++) { rtt = S->rtt_hist[j]; if (rtt < 0) addch(' '); else if (rtt == 0) addch('.'); else addch('!'); } addch('\n'); } move(w->_maxy - 1, 0); addstr(ctime(&now)); refresh(); } site_t * find_a_site_to_ping(void) { site_t *S = NULL; int i; site_t *best = NULL; time_t max_t = 0; time_t dt = 0; for (i = 0; i < NSites; i++) { S = &Sites[i]; dt = tvsub(&S->last_sent, &now_tv); if (dt < delay * 1000) continue; if (max_t > dt) continue; max_t = dt; best = S; } return best; } void main_loop(void) { fd_set R; struct timeval to; int maxfd; int x; site_t *S = NULL; time_t wait = 0; while (1) { FD_ZERO(&R); FD_SET(icmp_sock, &R); to.tv_sec = 0; to.tv_usec = wait > 200000 ? 200000 : wait < 1 ? 30000 : wait; wait = 0; maxfd = icmp_sock + 1; x = select(maxfd, &R, 0, 0, &to); if (x > 0) { if (FD_ISSET(icmp_sock, &R)) { if (recv_ping()) do_stats(); } } else if (x == 0) { gettimeofday(&now_tv, NULL); if ((S = find_a_site_to_ping())) wait = send_ping(S) * 2000; do_stats(); } } } void create_windows(void) { w = initscr(); do_stats(); } int in_cksum(unsigned short *ptr, int size) { register long sum; unsigned short oddbyte; register unsigned short answer; sum = 0; while (size > 1) { sum += *ptr++; size -= 2; } if (size == 1) { oddbyte = 0; *((unsigned char *)&oddbyte) = *(unsigned char *)ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return (answer); } int main(int argc, char *argv[]) { char myhostname[256]; struct hostent *h; int n; extern char *optarg; extern int optind; int c; progname = argv[0]; myhostname[0] = '\0'; delay = 3000; /* process options */ while ((c = getopt(argc, argv, "s:d:")) != -1) { switch (c) { case 's': strncpy(myhostname, optarg, 63); break; case 'd': delay = atoi(optarg); break; } } argc -= optind; argv += optind; if (argc < 1) { fprintf(stderr, "usage: %s [-s source hostname] [-d delay] hosts...\n", progname); exit(1); } NSites = 0; while (argc) { if (NSites == 100) break; memset(&Sites[NSites], '\0', sizeof(site_t)); for (n = 0; n < HIST_SIZE; n++) Sites[NSites].rtt_hist[n] = -1; strcpy(Sites[NSites].to_host, argv[0]); Sites[NSites].to_addr.sin_family = AF_INET; if ((h = gethostbyname(Sites[NSites].to_host))) { memcpy(&(Sites[NSites].to_addr.sin_addr.s_addr), *(h->h_addr_list), 4); } else { Sites[NSites].to_addr.sin_addr.s_addr = inet_addr(Sites[NSites].to_host); } gettimeofday(&(Sites[NSites].last_sent), 0); Sites[NSites].last_sent.tv_sec -= (delay / 1000); NSites++; argv++; argc--; } if (myhostname[0] == '\0') if (gethostname(myhostname, 63) < 0) { perror("gethostname"); exit(1); } memset((char *)&from_addr, '\0', sizeof(from_addr)); from_addr.sin_family = AF_INET; from_addr.sin_addr.s_addr = INADDR_ANY; datalen = DEF_DATALEN; icmp_pktsize = datalen + SIZE_ICMP_HDR; ident = getpid() & 0xffff; if ((proto = getprotobyname("icmp")) == 0) { fprintf(stderr, "unknown protocol: icmp\n"); exit(1); } if ((icmp_sock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { perror("icmp socket"); exit(1); } create_windows(); main_loop(); exit(0); } #define MAX_N_AVG 12 #ifdef __linux__ #define icmp_type type #define icmp_code code #define icmp_cksum checksum #define icmp_id un.echo.id #define icmp_seq un.echo.sequence #define icmp_gwaddr un.gateway #define ip_hl ihl #define ip_v version #define ip_tos tos #define ip_len tot_len #define ip_id id #define ip_off frag_off #define ip_ttl ttl #define ip_p protocol #define ip_sum check #define ip_src saddr #define ip_dst daddr #define icmp_type type #define icmp_code code #define icmp_cksum checksum #define icmp_id un.echo.id #define icmp_seq un.echo.sequence #define icmp_gwaddr un.gateway #endif /* __linux__ */ #ifndef __linux__ #define icmphdr icmp #define iphdr ip #endif /* __linux__ */ #ifndef ICMP_MINLEN #define ICMP_MINLEN 8 #endif site_t * find_site(from) struct sockaddr_in from; { int i; for (i = 0; i < NSites; i++) { if (from.sin_addr.s_addr == Sites[i].to_addr.sin_addr.s_addr) return &Sites[i]; } return NULL; } int recv_ping(void) { static int n; static int fromlen; static struct sockaddr_in from; int iphdrlen; int j; int offset; int k; struct iphdr *ip = NULL; register struct icmphdr *icp = NULL; char *source = NULL; struct timeval tv; struct timeval *tv1 = NULL; site_t *S = NULL; int N; fromlen = sizeof(from); n = recvfrom(icmp_sock, recv_pkt, sizeof(recv_pkt), 0, (struct sockaddr *)&from, &fromlen); gettimeofday(&tv, 0); source = inet_ntoa(from.sin_addr); ip = (struct iphdr *)recv_pkt; #if defined(__osf__) && __STDC__==1 #if BYTE_ORDER == BIG_ENDIAN iphdrlen = (ip->ip_vhl >> 4) << 2; #endif #if BYTE_ORDER == LITTLE_ENDIAN iphdrlen = (ip->ip_vhl & 0xF) << 2; #endif #else iphdrlen = ip->ip_hl << 2; #endif if (n < iphdrlen + ICMP_MINLEN) { fprintf(stderr, "packet too short (%d bytes) from %s\n", n, source); return 0; } n -= iphdrlen; icp = (struct icmphdr *)(recv_pkt + iphdrlen); if (icp->icmp_type != ICMP_ECHOREPLY) return 0; if (icp->icmp_id != ident) { return 0; } if ((S = find_site(from)) == NULL) return 0; #ifndef icmp_data tv1 = (struct timeval *)(icp + 1); #else tv1 = (struct timeval *)&icp->icmp_data[0]; #endif S->rtt = (double)tvsub(tv1, &tv) / 1000; if (S->rtt < 1.0) S->rtt = 1.0; S->ttl = ip->ip_ttl; N = ++S->nrecv; if (N >= MAX_N_AVG) N = MAX_N_AVG; S->avrtt = ((S->avrtt * (N - 1)) + S->rtt) / N; offset = ntohs(icp->icmp_seq) > S->high_seq; assert(offset >= 0); if (offset > 0) { for (j = 0; j < HIST_SIZE; j++) { k = j + offset; S->rtt_hist[j] = k < HIST_SIZE ? S->rtt_hist[k] : 0; } S->high_seq = ntohs(icp->icmp_seq); } S->rtt_hist[HIST_SIZE - 1] = (int)(S->rtt + 0.5); if (offset > 0) { for (j = 0; j < HIST_SIZE; j++) { k = j + offset; S->ttl_hist[j] = k < HIST_SIZE ? S->ttl_hist[k] : 0; } S->high_seq = ntohs(icp->icmp_seq); } S->ttl_hist[HIST_SIZE - 1] = S->ttl; return 1; } time_t send_ping(site_t * S) { time_t wait = 0; register int i; register struct icmphdr *icp; struct timeval *tv; int offset, j, k; memset(send_pkt, '\0', sizeof(send_pkt)); icp = (struct icmphdr *)send_pkt; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = ident; icp->icmp_seq = htons(S->npkts_sent++); tv = (struct timeval *)(send_pkt + SIZE_ICMP_HDR); gettimeofday(tv, 0); S->last_sent = *tv; icp->icmp_cksum = in_cksum((unsigned short *)icp, icmp_pktsize); i = sendto(icmp_sock, send_pkt, icmp_pktsize, 0, (struct sockaddr *)&(S->to_addr), sizeof(struct sockaddr_in)); offset = (S->npkts_sent - 1) - S->high_seq; assert(offset >= 0); if (offset > 0) { for (j = 0; j < HIST_SIZE; j++) { k = j + offset; S->rtt_hist[j] = k < HIST_SIZE ? S->rtt_hist[k] : 0; } S->high_seq = S->npkts_sent - 1; } return (time_t) (S->avrtt + 0.5); } int tvsub(struct timeval *t1, struct timeval *t2) { return (t2->tv_sec - t1->tv_sec) * 1000000 + (t2->tv_usec - t1->tv_usec); } @ 1.10 log @use htons() for icp->icmp_seq @ text @d2 2 a3 2 * $Id: mping.c,v 1.9 2002/01/31 04:56:11 wessels Exp wessels $ * d5 1 a5 1 * d7 1 a7 1 * d64 1 a64 1 static int delay; /* milliseconds */ d81 1 a81 1 } site_t; d99 1 a99 1 static void d159 2 a160 2 (int) (S->avrtt + 0.5), /*ttl_min, S->ttl, ttl_max,*/ d203 1 a203 1 void d229 1 a229 1 wait = send_ping(S) * 2000; d235 1 a235 1 void d242 1 a242 1 int d258 1 a258 1 *((unsigned char *) &oddbyte) = *(unsigned char *) ptr; d306 1 a306 1 break; d332 1 a332 1 memset((char *) &from_addr, '\0', sizeof(from_addr)); d381 1 a381 1 #endif /* __linux__ */ d386 1 a386 1 #endif /* __linux__ */ d394 1 a394 1 struct sockaddr_in from; d404 1 a404 1 int d425 1 a425 1 (struct sockaddr *) &from, &fromlen); d429 1 a429 1 ip = (struct iphdr *) recv_pkt; d448 1 a448 1 icp = (struct icmphdr *) (recv_pkt + iphdrlen); d460 1 a460 1 tv1 = (struct timeval *) (icp + 1); d462 1 a462 1 tv1 = (struct timeval *) &icp->icmp_data[0]; d464 1 a464 1 S->rtt = (double) tvsub(tv1, &tv) / 1000; d481 1 a481 1 S->high_seq = ntohs(icp->icmp_seq); d483 1 a483 1 S->rtt_hist[HIST_SIZE - 1] = (int) (S->rtt + 0.5); d490 1 a490 1 S->high_seq = ntohs(icp->icmp_seq); d498 2 a499 2 time_t send_ping(site_t *S) d509 1 a509 1 icp = (struct icmphdr *) send_pkt; d515 1 a515 1 tv = (struct timeval *) (send_pkt + SIZE_ICMP_HDR); d518 1 a518 1 icp->icmp_cksum = in_cksum((unsigned short *) icp, icmp_pktsize); d521 1 a521 1 (struct sockaddr *) &(S->to_addr), sizeof(struct sockaddr_in)); d536 1 a536 1 int @ 1.9 log @copyright, how to compile @ text @d2 1 a2 1 * $Id$ d474 1 a474 1 offset = icp->icmp_seq > S->high_seq; d481 1 a481 1 S->high_seq = icp->icmp_seq; d490 1 a490 1 S->high_seq = icp->icmp_seq; d514 1 a514 1 icp->icmp_seq = S->npkts_sent++; @ 1.8 log @handle the case when ICMP rtt < 1msec by rounding up to 1msec also indenting and ansi-fying @ text @d1 10 @ 1.7 log @gindent @ text @d54 1 a54 1 static int delay; /* milliseconds */ d79 1 a79 1 void create_windows(); d81 4 a84 4 void main_loop(); int recv_ping(); void send_next_ping(); time_t send_ping(); d89 2 a90 1 static void do_stats() d150 1 a150 1 /*ttl_min, S->ttl, ttl_max, */ d173 1 a173 1 find_a_site_to_ping(void) d193 2 a194 1 void main_loop() d219 2 a220 3 wait = send_ping(S) * 2000; else do_stats(); d225 2 a226 1 void create_windows() d232 2 a233 1 int in_cksum(unsigned short *ptr, int size) d258 2 a259 1 int main(int argc, char *argv[]) d296 1 a296 1 break; a321 5 if ((h = gethostbyname(myhostname)) == NULL) { fprintf(stderr, "gethostbyname(%s) failed\n", myhostname); exit(1); } d383 1 a383 1 find_site(from) d394 2 a395 1 int recv_ping() d455 2 d488 2 a489 2 time_t send_ping(site_t * S) d526 2 a527 1 int tvsub(struct timeval *t1, struct timeval *t2) @ 1.6 log @*** empty log message *** @ text @d54 1 a54 1 static int delay; /* milliseconds */ d89 1 a89 2 static void do_stats() d149 1 a149 1 /*ttl_min, S->ttl, ttl_max,*/ d172 1 a172 1 find_a_site_to_ping(void) d192 1 a192 2 void main_loop() d217 1 a217 1 wait = send_ping(S) * 2000; d219 1 a219 1 do_stats(); d224 1 a224 2 void create_windows() d230 1 a230 2 int in_cksum(unsigned short *ptr, int size) d255 1 a255 2 int main(int argc, char *argv[]) d292 1 a292 1 break; d384 1 a384 1 find_site(from) d395 1 a395 2 int recv_ping() d486 2 a487 2 time_t send_ping(site_t *S) d524 1 a524 2 int tvsub(struct timeval *t1, struct timeval *t2) @ 1.5 log @make send_ping() return the average RTT for that site so main_loop() knows how long to wait @ text @d220 2 a221 1 do_stats(); @ 1.4 log @*** empty log message *** @ text @d84 1 a84 1 void send_ping(); a198 1 int sending; d201 1 d207 2 a208 2 to.tv_usec = sending ? 100000 : (delay > 500 ? 500000 : delay * 1000); sending = 0; d218 2 a219 5 sending = 0; if ((S = find_a_site_to_ping())) { send_ping(S); sending = 1; } d491 1 a491 1 void d494 1 a494 1 d525 1 @ 1.3 log @vircs !$ @ text @d16 1 a16 1 #if !defined(__sgi__) && !defined(__sun__) @ 1.2 log @*** empty log message *** @ text @a0 1 static char rcsid[] = "$Id$"; d16 1 a16 1 #if !defined(__sgi__) d54 1 a54 1 static int delay; d57 1 d73 3 a75 1 static site_t Sites[50]; d89 2 a90 1 static void do_stats() d146 1 a146 1 sprintf(buf, "%-8.8s %d/%d/%d, %dms, %d/%d/%d ttl, %d%% loss", d150 1 a150 1 ttl_min, S->ttl, ttl_max, d160 2 a162 2 else addch('.'); d172 23 a194 1 void main_loop() d197 1 a197 1 struct timeval to, now; d199 1 a199 1 int sending = 0; a200 1 int i; d206 3 a208 2 to.tv_sec = sending ? 0 : 1; to.tv_usec = 0; d217 1 a217 1 gettimeofday(&now, 0); d219 1 a219 3 for (i = 0; i < NSites; i++) { S = &Sites[i]; if (tvsub(&S->last_sent, &now) > delay * 1000) { a221 2 break; } d228 2 a229 1 void create_windows() d235 2 a236 1 int in_cksum(unsigned short *ptr, int size) d261 2 a262 1 int main(int argc, char *argv[]) d274 1 a274 1 delay = 5000; d284 1 a284 1 delay = 10 * atoi(optarg); d298 2 d314 1 a314 1 Sites[NSites].last_sent.tv_sec -= delay; d391 1 a391 1 find_site(from) d402 2 a403 1 int recv_ping() d494 2 a495 1 void send_ping(site_t * S) d531 2 a532 1 int tvsub(struct timeval *t1, struct timeval *t2) @ 1.1 log @Initial revision @ text @d1 1 @