1*cf5a6c84SAndroid Build Coastguard Worker /* ping.c - check network connectivity
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2014 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * Not in SUSv4.
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * Note: ping_group_range should never have existed. To disable it, do:
8*cf5a6c84SAndroid Build Coastguard Worker * echo 0 999999999 > /proc/sys/net/ipv4/ping_group_range
9*cf5a6c84SAndroid Build Coastguard Worker * (Android does this by default in its init script.)
10*cf5a6c84SAndroid Build Coastguard Worker *
11*cf5a6c84SAndroid Build Coastguard Worker * Yes, I wimped out and capped -s at sizeof(toybuf), waiting for a complaint...
12*cf5a6c84SAndroid Build Coastguard Worker
13*cf5a6c84SAndroid Build Coastguard Worker // -s > 4064 = sizeof(toybuf)-sizeof(struct icmphdr)-CMSG_SPACE(sizeof(uint8_t)), then kernel adds 20 bytes
14*cf5a6c84SAndroid Build Coastguard Worker USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>4064=56i%W#<0=3w#<0qf46I:[-46]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF))
15*cf5a6c84SAndroid Build Coastguard Worker USE_PING(OLDTOY(ping6, ping, TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF))
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker config PING
18*cf5a6c84SAndroid Build Coastguard Worker bool "ping"
19*cf5a6c84SAndroid Build Coastguard Worker default y
20*cf5a6c84SAndroid Build Coastguard Worker help
21*cf5a6c84SAndroid Build Coastguard Worker usage: ping [OPTIONS] HOST
22*cf5a6c84SAndroid Build Coastguard Worker
23*cf5a6c84SAndroid Build Coastguard Worker Check network connectivity by sending packets to a host and reporting
24*cf5a6c84SAndroid Build Coastguard Worker its response.
25*cf5a6c84SAndroid Build Coastguard Worker
26*cf5a6c84SAndroid Build Coastguard Worker Send ICMP ECHO_REQUEST packets to ipv4 or ipv6 addresses and prints each
27*cf5a6c84SAndroid Build Coastguard Worker echo it receives back, with round trip time. Returns true if host alive.
28*cf5a6c84SAndroid Build Coastguard Worker
29*cf5a6c84SAndroid Build Coastguard Worker Options:
30*cf5a6c84SAndroid Build Coastguard Worker -4, -6 Force IPv4 or IPv6
31*cf5a6c84SAndroid Build Coastguard Worker -c CNT Send CNT many packets (default 3, 0 = infinite)
32*cf5a6c84SAndroid Build Coastguard Worker -f Flood (print . and \b to show drops, default -c 15 -i 0.2)
33*cf5a6c84SAndroid Build Coastguard Worker -i TIME Interval between packets (default 1, need root for < .2)
34*cf5a6c84SAndroid Build Coastguard Worker -I IFACE/IP Source interface or address
35*cf5a6c84SAndroid Build Coastguard Worker -m MARK Tag outgoing packets using SO_MARK
36*cf5a6c84SAndroid Build Coastguard Worker -q Quiet (stops after one returns true if host is alive)
37*cf5a6c84SAndroid Build Coastguard Worker -s SIZE Data SIZE in bytes (default 56)
38*cf5a6c84SAndroid Build Coastguard Worker -t TTL Set Time To Live (number of hops)
39*cf5a6c84SAndroid Build Coastguard Worker -W SEC Seconds to wait for response after last -c packet (default 3)
40*cf5a6c84SAndroid Build Coastguard Worker -w SEC Exit after this many seconds
41*cf5a6c84SAndroid Build Coastguard Worker */
42*cf5a6c84SAndroid Build Coastguard Worker
43*cf5a6c84SAndroid Build Coastguard Worker #define FOR_ping
44*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
45*cf5a6c84SAndroid Build Coastguard Worker
46*cf5a6c84SAndroid Build Coastguard Worker #include <ifaddrs.h>
47*cf5a6c84SAndroid Build Coastguard Worker #include <netinet/ip_icmp.h>
48*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(char * I;long w,W,i,s,c,t,m;struct sockaddr * sa;int sock;unsigned long sent,recv,fugit,min,max;)49*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
50*cf5a6c84SAndroid Build Coastguard Worker char *I;
51*cf5a6c84SAndroid Build Coastguard Worker long w, W, i, s, c, t, m;
52*cf5a6c84SAndroid Build Coastguard Worker
53*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr *sa;
54*cf5a6c84SAndroid Build Coastguard Worker int sock;
55*cf5a6c84SAndroid Build Coastguard Worker unsigned long sent, recv, fugit, min, max;
56*cf5a6c84SAndroid Build Coastguard Worker )
57*cf5a6c84SAndroid Build Coastguard Worker
58*cf5a6c84SAndroid Build Coastguard Worker // Print a summary. Called as a single handler or at exit.
59*cf5a6c84SAndroid Build Coastguard Worker static void summary(int sig)
60*cf5a6c84SAndroid Build Coastguard Worker {
61*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(q) && TT.sent && TT.sa) {
62*cf5a6c84SAndroid Build Coastguard Worker printf("\n--- %s ping statistics ---\n", ntop(TT.sa));
63*cf5a6c84SAndroid Build Coastguard Worker printf("%lu packets transmitted, %lu received, %ld%% packet loss\n",
64*cf5a6c84SAndroid Build Coastguard Worker TT.sent, TT.recv, ((TT.sent-TT.recv)*100)/(TT.sent?TT.sent:1));
65*cf5a6c84SAndroid Build Coastguard Worker if (TT.recv)
66*cf5a6c84SAndroid Build Coastguard Worker printf("round-trip min/avg/max = %lu/%lu/%lu ms\n",
67*cf5a6c84SAndroid Build Coastguard Worker TT.min, TT.fugit/TT.recv, TT.max);
68*cf5a6c84SAndroid Build Coastguard Worker }
69*cf5a6c84SAndroid Build Coastguard Worker TT.sa = 0;
70*cf5a6c84SAndroid Build Coastguard Worker }
71*cf5a6c84SAndroid Build Coastguard Worker
72*cf5a6c84SAndroid Build Coastguard Worker // assumes aligned and can read even number of bytes
pingchksum(unsigned short * data,int len)73*cf5a6c84SAndroid Build Coastguard Worker static unsigned short pingchksum(unsigned short *data, int len)
74*cf5a6c84SAndroid Build Coastguard Worker {
75*cf5a6c84SAndroid Build Coastguard Worker unsigned short u = 0, d;
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker // circular carry is endian independent: bits from high byte go to low byte
78*cf5a6c84SAndroid Build Coastguard Worker while (len>0) {
79*cf5a6c84SAndroid Build Coastguard Worker d = *data++;
80*cf5a6c84SAndroid Build Coastguard Worker if (len == 1) d &= 255<<IS_BIG_ENDIAN;
81*cf5a6c84SAndroid Build Coastguard Worker if (d >= (u += d)) u++;
82*cf5a6c84SAndroid Build Coastguard Worker len -= 2;
83*cf5a6c84SAndroid Build Coastguard Worker }
84*cf5a6c84SAndroid Build Coastguard Worker
85*cf5a6c84SAndroid Build Coastguard Worker return u;
86*cf5a6c84SAndroid Build Coastguard Worker }
87*cf5a6c84SAndroid Build Coastguard Worker
xrecvmsgwait(int fd,struct msghdr * msg,int flag,union socksaddr * sa,int timeout)88*cf5a6c84SAndroid Build Coastguard Worker static int xrecvmsgwait(int fd, struct msghdr *msg, int flag,
89*cf5a6c84SAndroid Build Coastguard Worker union socksaddr *sa, int timeout)
90*cf5a6c84SAndroid Build Coastguard Worker {
91*cf5a6c84SAndroid Build Coastguard Worker socklen_t sl = sizeof(*sa);
92*cf5a6c84SAndroid Build Coastguard Worker int len;
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker if (timeout >= 0) {
95*cf5a6c84SAndroid Build Coastguard Worker struct pollfd pfd;
96*cf5a6c84SAndroid Build Coastguard Worker
97*cf5a6c84SAndroid Build Coastguard Worker pfd.fd = fd;
98*cf5a6c84SAndroid Build Coastguard Worker pfd.events = POLLIN;
99*cf5a6c84SAndroid Build Coastguard Worker if (!xpoll(&pfd, 1, timeout)) return 0;
100*cf5a6c84SAndroid Build Coastguard Worker }
101*cf5a6c84SAndroid Build Coastguard Worker
102*cf5a6c84SAndroid Build Coastguard Worker msg->msg_name = (void *)sa;
103*cf5a6c84SAndroid Build Coastguard Worker msg->msg_namelen = sl;
104*cf5a6c84SAndroid Build Coastguard Worker len = recvmsg(fd, msg, flag);
105*cf5a6c84SAndroid Build Coastguard Worker if (len<0) perror_exit("recvmsg");
106*cf5a6c84SAndroid Build Coastguard Worker
107*cf5a6c84SAndroid Build Coastguard Worker return len;
108*cf5a6c84SAndroid Build Coastguard Worker }
109*cf5a6c84SAndroid Build Coastguard Worker
ping_main(void)110*cf5a6c84SAndroid Build Coastguard Worker void ping_main(void)
111*cf5a6c84SAndroid Build Coastguard Worker {
112*cf5a6c84SAndroid Build Coastguard Worker struct addrinfo *ai, *ai2;
113*cf5a6c84SAndroid Build Coastguard Worker struct ifaddrs *ifa, *ifa2 = 0;
114*cf5a6c84SAndroid Build Coastguard Worker struct icmphdr *ih = (void *)toybuf;
115*cf5a6c84SAndroid Build Coastguard Worker struct msghdr msg;
116*cf5a6c84SAndroid Build Coastguard Worker struct cmsghdr *cmsg;
117*cf5a6c84SAndroid Build Coastguard Worker struct iovec iov;
118*cf5a6c84SAndroid Build Coastguard Worker union socksaddr srcaddr, srcaddr2;
119*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr *sa = (void *)&srcaddr;
120*cf5a6c84SAndroid Build Coastguard Worker int family = 0, ttl = 0, len;
121*cf5a6c84SAndroid Build Coastguard Worker long long tnext, tW, tnow, tw;
122*cf5a6c84SAndroid Build Coastguard Worker unsigned short seq = 0, pkttime;
123*cf5a6c84SAndroid Build Coastguard Worker
124*cf5a6c84SAndroid Build Coastguard Worker // Set nonstatic default values
125*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(i)) TT.i = FLAG(f) ? 200 : 1000;
126*cf5a6c84SAndroid Build Coastguard Worker else if (TT.i<200 && geteuid()) error_exit("need root for -i <200");
127*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(s)) TT.s = 56; // 64-PHDR_LEN
128*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f) && !FLAG(c)) TT.c = 15;
129*cf5a6c84SAndroid Build Coastguard Worker
130*cf5a6c84SAndroid Build Coastguard Worker // ipv4 or ipv6? (0 = autodetect if -I or arg have only one address type.)
131*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(6) || strchr(toys.which->name, '6')) family = AF_INET6;
132*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(4)) family = AF_INET;
133*cf5a6c84SAndroid Build Coastguard Worker else family = 0;
134*cf5a6c84SAndroid Build Coastguard Worker
135*cf5a6c84SAndroid Build Coastguard Worker // If -I srcaddr look it up. Allow numeric address of correct type.
136*cf5a6c84SAndroid Build Coastguard Worker memset(&srcaddr, 0, sizeof(srcaddr));
137*cf5a6c84SAndroid Build Coastguard Worker if (TT.I) {
138*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(6) && inet_pton(AF_INET, TT.I, (void *)&srcaddr.in.sin_addr))
139*cf5a6c84SAndroid Build Coastguard Worker family = AF_INET;
140*cf5a6c84SAndroid Build Coastguard Worker else if (!FLAG(4) && inet_pton(AF_INET6, TT.I, (void *)&srcaddr.in6.sin6_addr))
141*cf5a6c84SAndroid Build Coastguard Worker family = AF_INET6;
142*cf5a6c84SAndroid Build Coastguard Worker else if (getifaddrs(&ifa2)) perror_exit("getifaddrs");
143*cf5a6c84SAndroid Build Coastguard Worker }
144*cf5a6c84SAndroid Build Coastguard Worker
145*cf5a6c84SAndroid Build Coastguard Worker // Look up HOST address, filtering for correct type and interface.
146*cf5a6c84SAndroid Build Coastguard Worker // If -I but no -46 then find compatible type between -I and HOST
147*cf5a6c84SAndroid Build Coastguard Worker ai2 = xgetaddrinfo(*toys.optargs, 0, family, 0, 0, 0);
148*cf5a6c84SAndroid Build Coastguard Worker for (ai = ai2; ai; ai = ai->ai_next) {
149*cf5a6c84SAndroid Build Coastguard Worker
150*cf5a6c84SAndroid Build Coastguard Worker // correct type?
151*cf5a6c84SAndroid Build Coastguard Worker if (family && family!=ai->ai_family) continue;
152*cf5a6c84SAndroid Build Coastguard Worker if (ai->ai_family!=AF_INET && ai->ai_family!=AF_INET6) continue;
153*cf5a6c84SAndroid Build Coastguard Worker
154*cf5a6c84SAndroid Build Coastguard Worker // correct interface?
155*cf5a6c84SAndroid Build Coastguard Worker if (!TT.I || !ifa2) break;
156*cf5a6c84SAndroid Build Coastguard Worker for (ifa = ifa2; ifa; ifa = ifa->ifa_next) {
157*cf5a6c84SAndroid Build Coastguard Worker if (!ifa->ifa_addr || ifa->ifa_addr->sa_family!=ai->ai_family
158*cf5a6c84SAndroid Build Coastguard Worker || strcmp(ifa->ifa_name, TT.I)) continue;
159*cf5a6c84SAndroid Build Coastguard Worker sa = (void *)ifa->ifa_addr;
160*cf5a6c84SAndroid Build Coastguard Worker
161*cf5a6c84SAndroid Build Coastguard Worker break;
162*cf5a6c84SAndroid Build Coastguard Worker }
163*cf5a6c84SAndroid Build Coastguard Worker if (ifa) break;
164*cf5a6c84SAndroid Build Coastguard Worker }
165*cf5a6c84SAndroid Build Coastguard Worker
166*cf5a6c84SAndroid Build Coastguard Worker if (!ai)
167*cf5a6c84SAndroid Build Coastguard Worker error_exit("no v%d addr for -I %s", 4+2*(family==AF_INET6), TT.I);
168*cf5a6c84SAndroid Build Coastguard Worker TT.sa = ai->ai_addr;
169*cf5a6c84SAndroid Build Coastguard Worker
170*cf5a6c84SAndroid Build Coastguard Worker // Open DGRAM socket
171*cf5a6c84SAndroid Build Coastguard Worker sa->sa_family = ai->ai_family;
172*cf5a6c84SAndroid Build Coastguard Worker TT.sock = socket(ai->ai_family, SOCK_DGRAM,
173*cf5a6c84SAndroid Build Coastguard Worker len = (ai->ai_family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
174*cf5a6c84SAndroid Build Coastguard Worker if (TT.sock == -1) {
175*cf5a6c84SAndroid Build Coastguard Worker perror_msg("socket SOCK_DGRAM %x", len);
176*cf5a6c84SAndroid Build Coastguard Worker if (errno == EACCES) {
177*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "Kernel bug workaround:\n"
178*cf5a6c84SAndroid Build Coastguard Worker "echo 0 99999999 | sudo tee /proc/sys/net/ipv4/ping_group_range\n");
179*cf5a6c84SAndroid Build Coastguard Worker }
180*cf5a6c84SAndroid Build Coastguard Worker xexit();
181*cf5a6c84SAndroid Build Coastguard Worker }
182*cf5a6c84SAndroid Build Coastguard Worker if (TT.I) xbind(TT.sock, sa, sizeof(srcaddr));
183*cf5a6c84SAndroid Build Coastguard Worker
184*cf5a6c84SAndroid Build Coastguard Worker len = 1;
185*cf5a6c84SAndroid Build Coastguard Worker xsetsockopt(TT.sock, SOL_IP, IP_RECVTTL, &len, sizeof(len));
186*cf5a6c84SAndroid Build Coastguard Worker
187*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(m)) {
188*cf5a6c84SAndroid Build Coastguard Worker len = TT.m;
189*cf5a6c84SAndroid Build Coastguard Worker xsetsockopt(TT.sock, SOL_SOCKET, SO_MARK, &len, sizeof(len));
190*cf5a6c84SAndroid Build Coastguard Worker }
191*cf5a6c84SAndroid Build Coastguard Worker
192*cf5a6c84SAndroid Build Coastguard Worker if (TT.t) {
193*cf5a6c84SAndroid Build Coastguard Worker len = TT.t;
194*cf5a6c84SAndroid Build Coastguard Worker if (ai->ai_family == AF_INET)
195*cf5a6c84SAndroid Build Coastguard Worker xsetsockopt(TT.sock, IPPROTO_IP, IP_TTL, &len, 4);
196*cf5a6c84SAndroid Build Coastguard Worker else xsetsockopt(TT.sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &len, sizeof(len));
197*cf5a6c84SAndroid Build Coastguard Worker }
198*cf5a6c84SAndroid Build Coastguard Worker
199*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(q)) {
200*cf5a6c84SAndroid Build Coastguard Worker printf("Ping %s (%s)", *toys.optargs, ntop(TT.sa));
201*cf5a6c84SAndroid Build Coastguard Worker if (TT.I) {
202*cf5a6c84SAndroid Build Coastguard Worker *toybuf = 0;
203*cf5a6c84SAndroid Build Coastguard Worker printf(" from %s (%s)", TT.I, ntop(sa));
204*cf5a6c84SAndroid Build Coastguard Worker }
205*cf5a6c84SAndroid Build Coastguard Worker // 20 byte TCP header, 8 byte ICMP header, plus data payload
206*cf5a6c84SAndroid Build Coastguard Worker printf(": %ld(%ld) bytes.\n", TT.s, TT.s+28);
207*cf5a6c84SAndroid Build Coastguard Worker }
208*cf5a6c84SAndroid Build Coastguard Worker
209*cf5a6c84SAndroid Build Coastguard Worker TT.min = ULONG_MAX;
210*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 1;
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker tW = tw = 0;
213*cf5a6c84SAndroid Build Coastguard Worker tnext = millitime();
214*cf5a6c84SAndroid Build Coastguard Worker if (TT.w) tw = TT.w*1000+tnext;
215*cf5a6c84SAndroid Build Coastguard Worker
216*cf5a6c84SAndroid Build Coastguard Worker memset(&msg, 0, sizeof(msg));
217*cf5a6c84SAndroid Build Coastguard Worker // left enought space to store ttl value
218*cf5a6c84SAndroid Build Coastguard Worker len = CMSG_SPACE(sizeof(uint8_t));
219*cf5a6c84SAndroid Build Coastguard Worker iov.iov_base = (void *)toybuf;
220*cf5a6c84SAndroid Build Coastguard Worker iov.iov_len = sizeof(toybuf) - len;
221*cf5a6c84SAndroid Build Coastguard Worker msg.msg_iov = &iov;
222*cf5a6c84SAndroid Build Coastguard Worker msg.msg_iovlen = 1;
223*cf5a6c84SAndroid Build Coastguard Worker msg.msg_control = &toybuf[iov.iov_len];
224*cf5a6c84SAndroid Build Coastguard Worker msg.msg_controllen = len;
225*cf5a6c84SAndroid Build Coastguard Worker
226*cf5a6c84SAndroid Build Coastguard Worker sigatexit(summary);
227*cf5a6c84SAndroid Build Coastguard Worker
228*cf5a6c84SAndroid Build Coastguard Worker // Send/receive packets
229*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
230*cf5a6c84SAndroid Build Coastguard Worker int waitms = INT_MAX;
231*cf5a6c84SAndroid Build Coastguard Worker
232*cf5a6c84SAndroid Build Coastguard Worker // Exit due to timeout? (TODO: timeout is after last packet, waiting if
233*cf5a6c84SAndroid Build Coastguard Worker // any packets ever dropped. Not timeout since packet was dropped.)
234*cf5a6c84SAndroid Build Coastguard Worker tnow = millitime();
235*cf5a6c84SAndroid Build Coastguard Worker if (tW) {
236*cf5a6c84SAndroid Build Coastguard Worker if (0>=(waitms = tW-tnow) || !(TT.sent-TT.recv)) break;
237*cf5a6c84SAndroid Build Coastguard Worker waitms = tW-tnow;
238*cf5a6c84SAndroid Build Coastguard Worker }
239*cf5a6c84SAndroid Build Coastguard Worker if (tw) {
240*cf5a6c84SAndroid Build Coastguard Worker if (tnow>tw) break;
241*cf5a6c84SAndroid Build Coastguard Worker else if (waitms>tw-tnow) waitms = tw-tnow;
242*cf5a6c84SAndroid Build Coastguard Worker }
243*cf5a6c84SAndroid Build Coastguard Worker
244*cf5a6c84SAndroid Build Coastguard Worker // Time to send the next packet?
245*cf5a6c84SAndroid Build Coastguard Worker if (!tW && tnext-tnow <= 0) {
246*cf5a6c84SAndroid Build Coastguard Worker tnext += TT.i;
247*cf5a6c84SAndroid Build Coastguard Worker
248*cf5a6c84SAndroid Build Coastguard Worker memset(ih, 0, sizeof(*ih));
249*cf5a6c84SAndroid Build Coastguard Worker ih->type = (ai->ai_family == AF_INET) ? 8 : 128;
250*cf5a6c84SAndroid Build Coastguard Worker ih->un.echo.id = getpid();
251*cf5a6c84SAndroid Build Coastguard Worker ih->un.echo.sequence = ++seq;
252*cf5a6c84SAndroid Build Coastguard Worker if (TT.s >= 4) *(unsigned *)(ih+1) = tnow;
253*cf5a6c84SAndroid Build Coastguard Worker
254*cf5a6c84SAndroid Build Coastguard Worker ih->checksum = pingchksum((void *)toybuf, TT.s+sizeof(*ih));
255*cf5a6c84SAndroid Build Coastguard Worker xsendto(TT.sock, toybuf, TT.s+sizeof(*ih), TT.sa);
256*cf5a6c84SAndroid Build Coastguard Worker TT.sent++;
257*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f) && !FLAG(q)) xputc('.');
258*cf5a6c84SAndroid Build Coastguard Worker
259*cf5a6c84SAndroid Build Coastguard Worker // last packet?
260*cf5a6c84SAndroid Build Coastguard Worker if (TT.c) if (!--TT.c) {
261*cf5a6c84SAndroid Build Coastguard Worker tW = tnow + TT.W*1000;
262*cf5a6c84SAndroid Build Coastguard Worker waitms = 1; // check for immediate return even when W=0
263*cf5a6c84SAndroid Build Coastguard Worker }
264*cf5a6c84SAndroid Build Coastguard Worker }
265*cf5a6c84SAndroid Build Coastguard Worker
266*cf5a6c84SAndroid Build Coastguard Worker // This is down here so it's against new period if we just sent a packet
267*cf5a6c84SAndroid Build Coastguard Worker if (!tW && waitms>tnext-tnow) waitms = tnext-tnow;
268*cf5a6c84SAndroid Build Coastguard Worker
269*cf5a6c84SAndroid Build Coastguard Worker // wait for next packet or timeout
270*cf5a6c84SAndroid Build Coastguard Worker
271*cf5a6c84SAndroid Build Coastguard Worker if (waitms<0) waitms = 0;
272*cf5a6c84SAndroid Build Coastguard Worker if (!(len = xrecvmsgwait(TT.sock, &msg, 0, &srcaddr2, waitms)))
273*cf5a6c84SAndroid Build Coastguard Worker continue;
274*cf5a6c84SAndroid Build Coastguard Worker
275*cf5a6c84SAndroid Build Coastguard Worker TT.recv++;
276*cf5a6c84SAndroid Build Coastguard Worker TT.fugit += (pkttime = millitime()-*(unsigned *)(ih+1));
277*cf5a6c84SAndroid Build Coastguard Worker if (pkttime < TT.min) TT.min = pkttime;
278*cf5a6c84SAndroid Build Coastguard Worker if (pkttime > TT.max) TT.max = pkttime;
279*cf5a6c84SAndroid Build Coastguard Worker
280*cf5a6c84SAndroid Build Coastguard Worker // reply id == 0 for ipv4, 129 for ipv6
281*cf5a6c84SAndroid Build Coastguard Worker
282*cf5a6c84SAndroid Build Coastguard Worker cmsg = CMSG_FIRSTHDR(&msg);
283*cf5a6c84SAndroid Build Coastguard Worker for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
284*cf5a6c84SAndroid Build Coastguard Worker if (cmsg->cmsg_level == IPPROTO_IP
285*cf5a6c84SAndroid Build Coastguard Worker && cmsg->cmsg_type == IP_TTL) {
286*cf5a6c84SAndroid Build Coastguard Worker ttl = *(uint8_t *)CMSG_DATA(cmsg);
287*cf5a6c84SAndroid Build Coastguard Worker break;
288*cf5a6c84SAndroid Build Coastguard Worker }
289*cf5a6c84SAndroid Build Coastguard Worker };
290*cf5a6c84SAndroid Build Coastguard Worker
291*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(q)) {
292*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f)) xputc('\b');
293*cf5a6c84SAndroid Build Coastguard Worker else {
294*cf5a6c84SAndroid Build Coastguard Worker printf("%d bytes from %s: icmp_seq=%d ttl=%d", len, ntop(&srcaddr2.s),
295*cf5a6c84SAndroid Build Coastguard Worker ih->un.echo.sequence, ttl);
296*cf5a6c84SAndroid Build Coastguard Worker if (len >= sizeof(*ih)+4) printf(" time=%u ms", pkttime);
297*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
298*cf5a6c84SAndroid Build Coastguard Worker }
299*cf5a6c84SAndroid Build Coastguard Worker }
300*cf5a6c84SAndroid Build Coastguard Worker
301*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 0;
302*cf5a6c84SAndroid Build Coastguard Worker }
303*cf5a6c84SAndroid Build Coastguard Worker
304*cf5a6c84SAndroid Build Coastguard Worker // summary(0) gets called for us atexit.
305*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) {
306*cf5a6c84SAndroid Build Coastguard Worker freeaddrinfo(ai2);
307*cf5a6c84SAndroid Build Coastguard Worker if (ifa2) freeifaddrs(ifa2);
308*cf5a6c84SAndroid Build Coastguard Worker }
309*cf5a6c84SAndroid Build Coastguard Worker }
310