~arky/ubuntu/lucid/iputils/fix-512227

« back to all changes in this revision

Viewing changes to ping_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2002-04-21 02:07:55 UTC
  • Revision ID: james.westby@ubuntu.com-20020421020755-ttbj5lnh9l137vct
Tags: upstream-20020124
ImportĀ upstreamĀ versionĀ 20020124

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "ping_common.h"
 
2
#include <ctype.h>
 
3
#include <sched.h>
 
4
 
 
5
int options;
 
6
int moptions;
 
7
 
 
8
int sndbuf;
 
9
int ttl, loop;
 
10
int rtt;
 
11
int rtt_addend;
 
12
__u16 acked;
 
13
 
 
14
int mx_dup_ck = MAX_DUP_CHK;
 
15
char rcvd_tbl[MAX_DUP_CHK / 8];
 
16
 
 
17
 
 
18
/* counters */
 
19
long npackets;                  /* max packets to transmit */
 
20
long nreceived;                 /* # of packets we got back */
 
21
long nrepeats;                  /* number of duplicates */
 
22
long ntransmitted;              /* sequence # for outbound packets = #sent */
 
23
long nchecksum;                 /* replies with bad checksum */
 
24
long nerrors;                   /* icmp errors */
 
25
int interval = 1000;            /* interval between packets (msec) */
 
26
int preload;
 
27
int deadline = 0;               /* time to die */
 
28
struct timeval start_time, cur_time;
 
29
volatile int exiting;
 
30
volatile int status_snapshot;
 
31
int confirm = 0;
 
32
 
 
33
/* Stupid workarounds for bugs/missing functionality in older linuces.
 
34
 * confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
 
35
 * i.e. for linux-2.2 */
 
36
int confirm_flag = MSG_CONFIRM;
 
37
/* And this is workaround for bug in IP_RECVERR on raw sockets which is present
 
38
 * in linux-2.2.[0-19], linux-2.4.[0-7] */
 
39
int working_recverr;
 
40
 
 
41
/* timing */
 
42
int timing;                     /* flag to do timing */
 
43
long tmin = LONG_MAX;           /* minimum round trip time */
 
44
long tmax;                      /* maximum round trip time */
 
45
long long tsum;                 /* sum of all times, for doing average */
 
46
long long tsum2;
 
47
int  pipesize = -1;
 
48
 
 
49
int datalen = DEFDATALEN;
 
50
 
 
51
char *hostname;
 
52
int uid;
 
53
int ident;                      /* process id to identify our packets */
 
54
 
 
55
static int screen_width = INT_MAX;
 
56
 
 
57
/* Fills all the outpack, excluding ICMP header, but _including_
 
58
 * timestamp area with supplied pattern.
 
59
 */
 
60
static void fill(char *patp)
 
61
{
 
62
        int ii, jj, kk;
 
63
        int pat[16];
 
64
        char *cp;
 
65
        char *bp = outpack+8;
 
66
 
 
67
        for (cp = patp; *cp; cp++) {
 
68
                if (!isxdigit(*cp)) {
 
69
                        fprintf(stderr,
 
70
                                "ping: patterns must be specified as hex digits.\n");
 
71
                        exit(2);
 
72
                }
 
73
        }
 
74
        ii = sscanf(patp,
 
75
            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
 
76
            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
 
77
            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
 
78
            &pat[13], &pat[14], &pat[15]);
 
79
 
 
80
        if (ii > 0) {
 
81
                for (kk = 0; kk <= maxpacket - (8 + ii); kk += ii)
 
82
                        for (jj = 0; jj < ii; ++jj)
 
83
                                bp[jj + kk] = pat[jj];
 
84
        }
 
85
        if (!(options & F_QUIET)) {
 
86
                printf("PATTERN: 0x");
 
87
                for (jj = 0; jj < ii; ++jj)
 
88
                        printf("%02x", bp[jj] & 0xFF);
 
89
                printf("\n");
 
90
        }
 
91
}
 
92
 
 
93
void common_options(int ch)
 
94
{
 
95
        switch(ch) {
 
96
        case 'a':
 
97
                options |= F_AUDIBLE;
 
98
                break;
 
99
        case 'A':
 
100
                options |= F_ADAPTIVE;
 
101
                break;
 
102
        case 'c':
 
103
                npackets = atoi(optarg);
 
104
                if (npackets <= 0) {
 
105
                        fprintf(stderr, "ping: bad number of packets to transmit.\n");
 
106
                        exit(2);
 
107
                }
 
108
                break;
 
109
        case 'd':
 
110
                options |= F_SO_DEBUG;
 
111
                break;
 
112
        case 'f':
 
113
                options |= F_FLOOD;
 
114
                setbuf(stdout, (char *)NULL);
 
115
                break;
 
116
        case 'i':               /* wait between sending packets */
 
117
        {
 
118
                if (strchr(optarg, '.')) {
 
119
                        float t;
 
120
                        if (sscanf(optarg, "%f", &t) != 1) {
 
121
                                fprintf(stderr, "ping: bad timing interval.\n");
 
122
                                exit(2);
 
123
                        }
 
124
                        interval = (int)(t*1000);
 
125
                } else if (sscanf(optarg, "%d", &interval) == 1) {
 
126
                        interval *= 1000;
 
127
                } else {
 
128
                        fprintf(stderr, "ping: bad timing interval.\n");
 
129
                        exit(2);
 
130
                }
 
131
 
 
132
                if (interval < 0) {
 
133
                        fprintf(stderr, "ping: bad timing interval.\n");
 
134
                        exit(2);
 
135
                }
 
136
                options |= F_INTERVAL;
 
137
                break;
 
138
        }
 
139
        case 'w':
 
140
                deadline = atoi(optarg);
 
141
                if (deadline < 0) {
 
142
                        fprintf(stderr, "ping: bad wait time.\n");
 
143
                        exit(2);
 
144
                }
 
145
                break;
 
146
        case 'l':
 
147
                preload = atoi(optarg);
 
148
                if (preload <= 0 || preload>mx_dup_ck) {
 
149
                        fprintf(stderr, "ping: bad preload value, should be 1..%d\n", mx_dup_ck);
 
150
                        exit(2);
 
151
                }
 
152
                if (uid && preload>3) {
 
153
                        fprintf(stderr, "ping: cannot set preload to value > 3\n");
 
154
                        exit(2);
 
155
                }
 
156
                break;
 
157
        case 'S':
 
158
                sndbuf = atoi(optarg);
 
159
                if (sndbuf <= 0) {
 
160
                        fprintf(stderr, "ping: bad sndbuf value.\n");
 
161
                        exit(2);
 
162
                }
 
163
                break;
 
164
        case 'n':
 
165
                options |= F_NUMERIC;
 
166
                break;
 
167
        case 'p':               /* fill buffer with user pattern */
 
168
                options |= F_PINGFILLED;
 
169
                fill(optarg);
 
170
                break;
 
171
        case 'q':
 
172
                options |= F_QUIET;
 
173
                break;
 
174
        case 'r':
 
175
                options |= F_SO_DONTROUTE;
 
176
                break;
 
177
        case 's':               /* size of packet to send */
 
178
                datalen = atoi(optarg);
 
179
                if (datalen < 0) {
 
180
                        fprintf(stderr, "ping: illegal negative packet size %d.\n", datalen);
 
181
                        exit(2);
 
182
                }
 
183
                break;
 
184
        case 'v':
 
185
                options |= F_VERBOSE;
 
186
                break;
 
187
        case 'L':
 
188
                moptions |= MULTICAST_NOLOOP;
 
189
                loop = 0;
 
190
                break;
 
191
        case 't':
 
192
                moptions |= MULTICAST_TTL;
 
193
                ttl = atoi(optarg);
 
194
                if (ttl < 0 || ttl > 255) {
 
195
                        fprintf(stderr, "ping: ttl %u out of range\n", ttl);
 
196
                        exit(2);
 
197
                }
 
198
                break;
 
199
        case 'U':
 
200
                options |= F_LATENCY;
 
201
                break;
 
202
        case 'V':
 
203
                printf("ping utility, iputils-ss%s\n", SNAPSHOT);
 
204
                exit(0);
 
205
        default:
 
206
                abort();
 
207
        }
 
208
}
 
209
 
 
210
 
 
211
static void sigexit(int signo)
 
212
{
 
213
        exiting = 1;
 
214
}
 
215
 
 
216
static void sigstatus(int signo)
 
217
{
 
218
        status_snapshot = 1;
 
219
}
 
220
 
 
221
 
 
222
int __schedule_exit(int next)
 
223
{
 
224
        unsigned long waittime;
 
225
        struct itimerval it;
 
226
 
 
227
        if (nreceived) {
 
228
                waittime = 2 * tmax;
 
229
                if (waittime<1000000)
 
230
                        waittime = 1000000;
 
231
        } else
 
232
                waittime = MAXWAIT*1000000;
 
233
 
 
234
        if (next<0 || next < waittime/1000)
 
235
                next = waittime/1000;
 
236
 
 
237
        it.it_interval.tv_sec = 0;
 
238
        it.it_interval.tv_usec = 0;
 
239
        it.it_value.tv_sec = waittime/1000000;
 
240
        it.it_value.tv_usec = waittime%1000000;
 
241
        setitimer(ITIMER_REAL, &it, NULL);
 
242
        return next;
 
243
}
 
244
 
 
245
static inline void update_interval(void)
 
246
{
 
247
        int est = rtt ? rtt/8 : interval*1000; 
 
248
 
 
249
        interval = (est+rtt_addend+500)/1000;
 
250
        if (uid && interval < MINUSERINTERVAL)
 
251
                interval = MINUSERINTERVAL;
 
252
}
 
253
 
 
254
/*
 
255
 * pinger --
 
256
 *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
 
257
 * will be added on by the kernel.  The ID field is our UNIX process ID,
 
258
 * and the sequence number is an ascending integer.  The first 8 bytes
 
259
 * of the data portion are used to hold a UNIX "timeval" struct in VAX
 
260
 * byte-order, to compute the round-trip time.
 
261
 */
 
262
int pinger(void)
 
263
{
 
264
        static int tokens;
 
265
        int i;
 
266
 
 
267
        /* Have we already sent enough? If we have, return an arbitrary positive value. */ 
 
268
        if (exiting || (npackets && ntransmitted >= npackets && !deadline))
 
269
                return 1000;
 
270
 
 
271
        /* Check that packets < rate*time + preload */
 
272
        if (cur_time.tv_sec == 0) {
 
273
                gettimeofday(&cur_time, NULL);
 
274
                tokens = interval*(preload-1);
 
275
        } else {
 
276
                long ntokens;
 
277
                struct timeval tv;
 
278
 
 
279
                gettimeofday(&tv, NULL);
 
280
                ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
 
281
                        (tv.tv_usec-cur_time.tv_usec)/1000;
 
282
                if (!interval) {
 
283
                        /* Case of unlimited flood is special;
 
284
                         * if we see no reply, they are limited to 100pps */
 
285
                        if (ntokens < MININTERVAL && in_flight() >= preload)
 
286
                                return MININTERVAL-ntokens;
 
287
                }
 
288
                ntokens += tokens;
 
289
                if (ntokens > interval*preload)
 
290
                        ntokens = interval*preload;
 
291
                if (ntokens < interval)
 
292
                        return interval - ntokens;
 
293
 
 
294
                cur_time = tv;
 
295
                tokens = ntokens - interval;
 
296
        }
 
297
 
 
298
resend:
 
299
        i = send_probe();
 
300
 
 
301
        if (i == 0) {
 
302
                advance_ntransmitted();
 
303
                if (!(options & F_QUIET) && (options & F_FLOOD)) {
 
304
                        /* Very silly, but without this output with
 
305
                         * high preload or pipe size is very confusing. */
 
306
                        if ((preload < screen_width && pipesize < screen_width) ||
 
307
                            in_flight() < screen_width)
 
308
                                write(STDOUT_FILENO, ".", 1);
 
309
                }
 
310
                return interval - tokens;
 
311
        }
 
312
 
 
313
        /* And handle various errors... */
 
314
        if (i > 0) {
 
315
                /* Apparently, it is some fatal bug. */
 
316
                abort();
 
317
        } else if (errno == ENOBUFS || errno == ENOMEM) {
 
318
                /* Device queue overflow or OOM. Packet is not sent. */
 
319
                tokens = 0;
 
320
                /* Slowdown. This works only in adaptive mode (option -A) */
 
321
                rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
 
322
                if (options&F_ADAPTIVE)
 
323
                        update_interval();
 
324
                return SCHINT(interval);
 
325
        } else if (errno == EAGAIN) {
 
326
                /* Socket buffer is full. */
 
327
                tokens += interval;
 
328
                return MININTERVAL;
 
329
        } else {
 
330
                if ((i=receive_error_msg()) > 0) {
 
331
                        /* An ICMP error arrived. */
 
332
                        tokens += interval;
 
333
                        return MININTERVAL;
 
334
                }
 
335
                /* Compatibility with old linuces. */
 
336
                if (i == 0 && confirm_flag && errno == EINVAL) {
 
337
                        confirm_flag = 0;
 
338
                        errno = 0;
 
339
                }
 
340
                if (!errno)
 
341
                        goto resend;
 
342
 
 
343
                /* Hard local error. Pretend we sent packet. */
 
344
                advance_ntransmitted();
 
345
 
 
346
                if (i == 0 && !(options & F_QUIET)) {
 
347
                        if (options & F_FLOOD)
 
348
                                write(STDOUT_FILENO, "E", 1);
 
349
                        else
 
350
                                perror("ping: sendmsg");
 
351
                }
 
352
                tokens = 0;
 
353
                return SCHINT(interval);
 
354
        }
 
355
}
 
356
 
 
357
/* Set socket buffers, "alloc" is an esimate of memory taken by single packet. */
 
358
 
 
359
void sock_setbufs(int icmp_sock, int alloc)
 
360
{
 
361
        int rcvbuf, hold;
 
362
        int tmplen = sizeof(hold);
 
363
 
 
364
        if (!sndbuf)
 
365
                sndbuf = alloc;
 
366
        setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf));
 
367
 
 
368
        rcvbuf = hold = alloc * preload;
 
369
        if (hold < 65536)
 
370
                hold = 65536;
 
371
        setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
 
372
        if (getsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) {
 
373
                if (hold < rcvbuf)
 
374
                        fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n");
 
375
        }
 
376
}
 
377
 
 
378
/* Protocol independent setup and parameter checks. */
 
379
 
 
380
void setup(int icmp_sock)
 
381
{
 
382
        int hold;
 
383
        struct timeval tv;
 
384
 
 
385
        if ((options & F_FLOOD) && !(options & F_INTERVAL))
 
386
                interval = 0;
 
387
 
 
388
        if (uid && interval < MINUSERINTERVAL) {
 
389
                fprintf(stderr, "ping: cannot flood; minimal interval, allowed for user, is %dms\n", MINUSERINTERVAL);
 
390
                exit(2);
 
391
        }
 
392
 
 
393
        if (interval >= INT_MAX/preload) {
 
394
                fprintf(stderr, "ping: illegal preload and/or interval\n");
 
395
                exit(2);
 
396
        }
 
397
 
 
398
        hold = 1;
 
399
        if (options & F_SO_DEBUG)
 
400
                setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold));
 
401
        if (options & F_SO_DONTROUTE)
 
402
                setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold));
 
403
 
 
404
#ifdef SO_TIMESTAMP
 
405
        if (!(options&F_LATENCY)) {
 
406
                int on = 1;
 
407
                if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
 
408
                        fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n");
 
409
        }
 
410
#endif
 
411
 
 
412
        /* Set some SNDTIMEO to prevent blocking forever
 
413
         * on sends, when device is too slow or stalls. Just put limit
 
414
         * of one second, or "interval", if it is less.
 
415
         */
 
416
        tv.tv_sec = 1;
 
417
        tv.tv_usec = 0;
 
418
        if (interval < 1000) {
 
419
                tv.tv_sec = 0;
 
420
                tv.tv_usec = 1000 * SCHINT(interval);
 
421
        }
 
422
        setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
 
423
 
 
424
        /* Set RCVTIMEO to "interval". Note, it is just an optimization
 
425
         * allowing to avoid redundant poll(). */
 
426
        tv.tv_sec = SCHINT(interval)/1000;
 
427
        tv.tv_usec = 1000*(SCHINT(interval)%1000);
 
428
        if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
 
429
                options |= F_FLOOD_POLL;
 
430
 
 
431
        if (!(options & F_PINGFILLED)) {
 
432
                int i;
 
433
                char *p = outpack+8;
 
434
 
 
435
                /* Do not forget about case of small datalen,
 
436
                 * fill timestamp area too!
 
437
                 */
 
438
                for (i = 0; i < datalen; ++i)
 
439
                        *p++ = i;
 
440
        }
 
441
 
 
442
        ident = getpid() & 0xFFFF;
 
443
 
 
444
        set_signal(SIGINT, sigexit);
 
445
        set_signal(SIGALRM, sigexit);
 
446
        set_signal(SIGQUIT, sigstatus);
 
447
 
 
448
        gettimeofday(&start_time, NULL);
 
449
 
 
450
        if (deadline) {
 
451
                struct itimerval it;
 
452
 
 
453
                it.it_interval.tv_sec = 0;
 
454
                it.it_interval.tv_usec = 0;
 
455
                it.it_value.tv_sec = deadline;
 
456
                it.it_value.tv_usec = 0;
 
457
                setitimer(ITIMER_REAL, &it, NULL);
 
458
        }
 
459
 
 
460
        if (isatty(STDOUT_FILENO)) {
 
461
                struct winsize w;
 
462
 
 
463
                if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
 
464
                        if (w.ws_col > 0)
 
465
                                screen_width = w.ws_col;
 
466
                }
 
467
        }
 
468
}
 
469
 
 
470
void main_loop(int icmp_sock, __u8 *packet, int packlen)
 
471
{
 
472
        char addrbuf[128];
 
473
        char ans_data[4096];
 
474
        struct iovec iov;
 
475
        struct msghdr msg;
 
476
        struct cmsghdr *c;
 
477
        int cc;
 
478
        int next;
 
479
        int polling;
 
480
 
 
481
        iov.iov_base = (char *)packet;
 
482
 
 
483
        for (;;) {
 
484
                /* Check exit conditions. */
 
485
                if (exiting)
 
486
                        break;
 
487
                if (npackets && nreceived >= npackets)
 
488
                        break;
 
489
                if (deadline && nerrors)
 
490
                        break;
 
491
                /* Check for and do special actions. */
 
492
                if (status_snapshot)
 
493
                        status();
 
494
 
 
495
                /* Send probes scheduled to this time. */
 
496
                do {
 
497
                        next = pinger();
 
498
                        next = schedule_exit(next);
 
499
                } while (next <= 0);
 
500
 
 
501
                /* "next" is time to send next probe, if positive.
 
502
                 * If next<=0 send now or as soon as possible. */
 
503
 
 
504
                /* Technical part. Looks wicked. Could be dropped,
 
505
                 * if everyone used the newest kernel. :-) 
 
506
                 * Its purpose is:
 
507
                 * 1. Provide intervals less than resolution of scheduler.
 
508
                 *    Solution: spinning.
 
509
                 * 2. Avoid use of poll(), when recvmsg() can provide
 
510
                 *    timed waiting (SO_RCVTIMEO). */
 
511
                polling = 0;
 
512
                if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
 
513
                        int recv_expected = in_flight();
 
514
 
 
515
                        /* If we are here, recvmsg() is unable to wait for
 
516
                         * required timeout. */ 
 
517
                        if (1000*next <= 1000000/(int)HZ) {
 
518
                                /* Very short timeout... So, if we wait for
 
519
                                 * something, we sleep for MININTERVAL.
 
520
                                 * Otherwise, spin! */
 
521
                                if (recv_expected) {
 
522
                                        next = MININTERVAL;
 
523
                                } else {
 
524
                                        next = 0;
 
525
                                        /* When spinning, no reasons to poll.
 
526
                                         * Use nonblocking recvmsg() instead. */
 
527
                                        polling = MSG_DONTWAIT;
 
528
                                        /* But yield yet. */
 
529
                                        sched_yield();
 
530
                                }
 
531
                        }
 
532
 
 
533
                        if (!polling &&
 
534
                            ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
 
535
                                struct pollfd pset;
 
536
                                pset.fd = icmp_sock;
 
537
                                pset.events = POLLIN|POLLERR;
 
538
                                pset.revents = 0;
 
539
                                if (poll(&pset, 1, next) < 1 ||
 
540
                                    !(pset.revents&(POLLIN|POLLERR)))
 
541
                                        continue;
 
542
                                polling = MSG_DONTWAIT;
 
543
                        }
 
544
                }
 
545
 
 
546
                for (;;) {
 
547
                        struct timeval *recv_timep = NULL;
 
548
                        struct timeval recv_time;
 
549
                        int not_ours = 0; /* Raw socket can receive messages
 
550
                                           * destined to other running pings. */
 
551
 
 
552
                        iov.iov_len = packlen;
 
553
                        msg.msg_name = addrbuf;
 
554
                        msg.msg_namelen = sizeof(addrbuf);
 
555
                        msg.msg_iov = &iov;
 
556
                        msg.msg_iovlen = 1;
 
557
                        msg.msg_control = ans_data;
 
558
                        msg.msg_controllen = sizeof(ans_data);
 
559
 
 
560
                        cc = recvmsg(icmp_sock, &msg, polling);
 
561
                        polling = MSG_DONTWAIT;
 
562
 
 
563
                        if (cc < 0) {
 
564
                                if (errno == EAGAIN || errno == EINTR)
 
565
                                        break;
 
566
                                if (!receive_error_msg()) {
 
567
                                        if (errno) {
 
568
                                                perror("ping: recvmsg");
 
569
                                                break;
 
570
                                        }
 
571
                                        not_ours = 1;
 
572
                                }
 
573
                        } else {
 
574
 
 
575
#ifdef SO_TIMESTAMP
 
576
                                for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
 
577
                                        if (c->cmsg_level != SOL_SOCKET ||
 
578
                                            c->cmsg_type != SO_TIMESTAMP)
 
579
                                                continue;
 
580
                                        if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
 
581
                                                continue;
 
582
                                        recv_timep = (struct timeval*)CMSG_DATA(c);
 
583
                                }
 
584
#endif
 
585
 
 
586
                                if ((options&F_LATENCY) || recv_timep == NULL) {
 
587
                                        if ((options&F_LATENCY) ||
 
588
                                            ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
 
589
                                                gettimeofday(&recv_time, NULL);
 
590
                                        recv_timep = &recv_time;
 
591
                                }
 
592
 
 
593
                                not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
 
594
                        }
 
595
 
 
596
                        /* See? ... someone runs another ping on this host. */ 
 
597
                        if (not_ours)
 
598
                                install_filter();
 
599
 
 
600
                        /* If nothing is in flight, "break" returns us to pinger. */
 
601
                        if (in_flight() == 0)
 
602
                                break;
 
603
 
 
604
                        /* Otherwise, try to recvmsg() again. recvmsg()
 
605
                         * is nonblocking after the first iteration, so that
 
606
                         * if nothing is queued, it will receive EAGAIN
 
607
                         * and return to pinger. */
 
608
                }
 
609
        }
 
610
        finish();
 
611
}
 
612
 
 
613
int gather_statistics(__u8 *ptr, int cc, __u16 seq, int hops,
 
614
                      int csfailed, struct timeval *tv, char *from)
 
615
{
 
616
        int dupflag = 0;
 
617
        long triptime = 0;
 
618
 
 
619
        ++nreceived;
 
620
        if (!csfailed)
 
621
                acknowledge(seq);
 
622
 
 
623
        if (timing && cc >= 8+sizeof(struct timeval)) {
 
624
                struct timeval tmp_tv;
 
625
                memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
 
626
 
 
627
restamp:
 
628
                tvsub(tv, &tmp_tv);
 
629
                triptime = tv->tv_sec * 1000000 + tv->tv_usec;
 
630
                if (triptime < 0) {
 
631
                        fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
 
632
                        triptime = 0;
 
633
                        if (!(options & F_LATENCY)) {
 
634
                                gettimeofday(tv, NULL);
 
635
                                options |= F_LATENCY;
 
636
                                goto restamp;
 
637
                        }
 
638
                }
 
639
                if (!csfailed) {
 
640
                        tsum += triptime;
 
641
                        tsum2 += (long long)triptime * (long long)triptime;
 
642
                        if (triptime < tmin)
 
643
                                tmin = triptime;
 
644
                        if (triptime > tmax)
 
645
                                tmax = triptime;
 
646
                        if (!rtt)
 
647
                                rtt = triptime*8;
 
648
                        else
 
649
                                rtt += triptime-rtt/8;
 
650
                        if (options&F_ADAPTIVE)
 
651
                                update_interval();
 
652
                }
 
653
        }
 
654
 
 
655
        if (csfailed) {
 
656
                ++nchecksum;
 
657
                --nreceived;
 
658
        } else if (TST(seq % mx_dup_ck)) {
 
659
                ++nrepeats;
 
660
                --nreceived;
 
661
                dupflag = 1;
 
662
        } else {
 
663
                SET(seq % mx_dup_ck);
 
664
                dupflag = 0;
 
665
        }
 
666
        confirm = confirm_flag;
 
667
 
 
668
        if (options & F_QUIET)
 
669
                return 1;
 
670
 
 
671
        if (options & F_FLOOD) {
 
672
                if (!csfailed)
 
673
                        write(STDOUT_FILENO, "\b \b", 3);
 
674
                else
 
675
                        write(STDOUT_FILENO, "\bC", 1);
 
676
        } else {
 
677
                int i;
 
678
                __u8 *cp, *dp;
 
679
                printf("%d bytes from %s: icmp_seq=%u", cc, from, seq);
 
680
 
 
681
                if (hops >= 0)
 
682
                        printf(" ttl=%d", hops);
 
683
 
 
684
                if (cc < datalen+8) {
 
685
                        printf(" (truncated)\n");
 
686
                        return 1;
 
687
                }
 
688
                if (timing) {
 
689
                        if (triptime >= 100000)
 
690
                                printf(" time=%ld ms", triptime/1000);
 
691
                        else if (triptime >= 10000)
 
692
                                printf(" time=%ld.%01ld ms", triptime/1000,
 
693
                                       (triptime%1000)/100);
 
694
                        else if (triptime >= 1000)
 
695
                                printf(" time=%ld.%02ld ms", triptime/1000,
 
696
                                       (triptime%1000)/10);
 
697
                        else
 
698
                                printf(" time=%ld.%03ld ms", triptime/1000,
 
699
                                       triptime%1000);
 
700
                }
 
701
                if (dupflag)
 
702
                        printf(" (DUP!)");
 
703
                if (csfailed)
 
704
                        printf(" (BAD CHECKSUM!)");
 
705
 
 
706
                /* check the data */
 
707
                cp = ((u_char*)ptr) + sizeof(struct timeval);
 
708
                dp = &outpack[8 + sizeof(struct timeval)];
 
709
                for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
 
710
                        if (*cp != *dp) {
 
711
                                printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
 
712
                                       i, *dp, *cp);
 
713
                                cp = (u_char*)ptr + sizeof(struct timeval);
 
714
                                for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
 
715
                                        if ((i % 32) == sizeof(struct timeval))
 
716
                                                printf("\n#%d\t", i);
 
717
                                        printf("%x ", *cp);
 
718
                                }
 
719
                                break;
 
720
                        }
 
721
                }
 
722
        }
 
723
        return 0;
 
724
}
 
725
 
 
726
static long llsqrt(long long a)
 
727
{
 
728
        long long prev = ~((long long)1 << 63);
 
729
        long long x = a;
 
730
 
 
731
        if (x > 0) {
 
732
                while (x < prev) {
 
733
                        prev = x;
 
734
                        x = (x+(a/x))/2;
 
735
                }
 
736
        }
 
737
 
 
738
        return (long)x;
 
739
}
 
740
 
 
741
/*
 
742
 * finish --
 
743
 *      Print out statistics, and give up.
 
744
 */
 
745
void finish(void)
 
746
{
 
747
        struct timeval tv = cur_time;
 
748
 
 
749
        tvsub(&tv, &start_time);
 
750
 
 
751
        putchar('\n');
 
752
        fflush(stdout);
 
753
        printf("--- %s ping statistics ---\n", hostname);
 
754
        printf("%ld packets transmitted, ", ntransmitted);
 
755
        printf("%ld received", nreceived);
 
756
        if (nrepeats)
 
757
                printf(", +%ld duplicates", nrepeats);
 
758
        if (nchecksum)
 
759
                printf(", +%ld corrupted", nchecksum);
 
760
        if (nerrors)
 
761
                printf(", +%ld errors", nerrors);
 
762
        if (ntransmitted) {
 
763
                printf(", %d%% loss",
 
764
                       (int) ((((long long)(ntransmitted - nreceived)) * 100) /
 
765
                              ntransmitted));
 
766
                printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
 
767
        }
 
768
        putchar('\n');
 
769
 
 
770
        if (nreceived && timing) {
 
771
                long tmdev;
 
772
 
 
773
                tsum /= nreceived + nrepeats;
 
774
                tsum2 /= nreceived + nrepeats;
 
775
                tmdev = llsqrt(tsum2 - tsum * tsum);
 
776
 
 
777
                printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
 
778
                       tmin/1000, tmin%1000,
 
779
                       (unsigned long)(tsum/1000), (long)(tsum%1000),
 
780
                       tmax/1000, tmax%1000,
 
781
                       tmdev/1000, tmdev%1000
 
782
                       );
 
783
        }
 
784
        if (pipesize > 1)
 
785
                printf(", pipe %d", pipesize);
 
786
        if (ntransmitted > 1 && (!interval || (options&(F_FLOOD|F_ADAPTIVE)))) {
 
787
                int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
 
788
                printf(", ipg/ewma %d.%03d/%d.%03d ms",
 
789
                       ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
 
790
        }
 
791
        putchar('\n');
 
792
        exit(deadline ? nreceived<npackets : nreceived==0);
 
793
}
 
794
 
 
795
 
 
796
void status(void)
 
797
{
 
798
        int loss = 0;
 
799
        long tavg = 0;
 
800
 
 
801
        status_snapshot = 0;
 
802
 
 
803
        if (ntransmitted)
 
804
                loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
 
805
 
 
806
        fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
 
807
 
 
808
        if (nreceived && timing) {
 
809
                tavg = tsum / (nreceived + nrepeats);
 
810
 
 
811
                fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
 
812
                       tmin/1000, tmin%1000,
 
813
                       tavg/1000, tavg%1000,
 
814
                       rtt/8000, (rtt/8)%1000,
 
815
                       tmax/1000, tmax%1000
 
816
                       );
 
817
        }
 
818
        fprintf(stderr, "\n");
 
819
}
 
820