1 /*
2     prints "status" message once per second to the commandline
3 
4     The status message indicates:
5     - the rate in packets-per-second
6     - %done
7     - estimated time remaining of the scan
8     - number of 'tcbs' (TCP control blocks) of active TCP connections
9 
10 */
11 #include "main-status.h"
12 #include "pixie-timer.h"
13 #include "unusedparm.h"
14 #include "main-globals.h"
15 #include "string_s.h"
16 #include <stdio.h>
17 
18 
19 
20 /***************************************************************************
21  * Print a status message about once-per-second to the command-line. This
22  * algorithm is a little funky because checking the timestamp on EVERY
23  * packet is slow.
24  ***************************************************************************/
25 void
status_print(struct Status * status,uint64_t count,uint64_t max_count,double x,uint64_t total_tcbs,uint64_t total_synacks,uint64_t total_syns,uint64_t exiting)26 status_print(
27     struct Status *status,
28     uint64_t count,
29     uint64_t max_count,
30     double x,
31     uint64_t total_tcbs,
32     uint64_t total_synacks,
33     uint64_t total_syns,
34     uint64_t exiting)
35 {
36     double elapsed_time;
37     double rate;
38     double now;
39     double percent_done;
40     double time_remaining;
41     uint64_t current_tcbs = 0;
42     uint64_t current_synacks = 0;
43     uint64_t current_syns = 0;
44     double tcb_rate = 0.0;
45     double synack_rate = 0.0;
46     double syn_rate = 0.0;
47 
48 
49     /*
50      * ####  FUGGLY TIME HACK  ####
51      *
52      * PF_RING doesn't timestamp packets well, so we can't base time from
53      * incoming packets. Checking the time ourself is too ugly on per-packet
54      * basis. Therefore, we are going to create a global variable that keeps
55      * the time, and update that variable whenever it's convienient. This
56      * is one of those convenient places.
57      */
58     global_now = time(0);
59 
60 
61     /* Get the time. NOTE: this is CLOCK_MONOTONIC_RAW on Linux, not
62      * wall-clock time. */
63     now = (double)pixie_gettime();
64 
65     /* Figure how many SECONDS have elapsed, in a floating point value.
66      * Since the above timestamp is in microseconds, we need to
67      * shift it by 1-million
68      */
69     elapsed_time = (now - status->last.clock)/1000000.0;
70     if (elapsed_time <= 0)
71         return;
72 
73     /* Figure out the "packets-per-second" number, which is just:
74      *
75      *  rate = packets_sent / elapsed_time;
76      */
77     rate = (count - status->last.count)*1.0/elapsed_time;
78 
79     /*
80      * Smooth the number by averaging over the last 8 seconds
81      */
82      status->last_rates[status->last_count++ & 0x7] = rate;
83      rate =     status->last_rates[0]
84                 + status->last_rates[1]
85                 + status->last_rates[2]
86                 + status->last_rates[3]
87                 + status->last_rates[4]
88                 + status->last_rates[5]
89                 + status->last_rates[6]
90                 + status->last_rates[7]
91                 ;
92     rate /= 8;
93     /*if (rate == 0)
94         return;*/
95 
96     /*
97      * Calculate "percent-done", which is just the total number of
98      * packets sent divided by the number we need to send.
99      */
100     percent_done = (double)(count*100.0/max_count);
101 
102 
103     /*
104      * Calulate the time remaining in the scan
105      */
106     time_remaining  = (1.0 - percent_done/100.0) * (max_count / rate);
107 
108     /*
109      * some other stats
110      */
111     if (total_tcbs) {
112         current_tcbs = total_tcbs - status->total_tcbs;
113         status->total_tcbs = total_tcbs;
114         tcb_rate = (1.0*current_tcbs)/elapsed_time;
115     }
116     if (total_synacks) {
117         current_synacks = total_synacks - status->total_synacks;
118         status->total_synacks = total_synacks;
119         synack_rate = (1.0*current_synacks)/elapsed_time;
120     }
121     if (total_syns) {
122         current_syns = total_syns - status->total_syns;
123         status->total_syns = total_syns;
124         syn_rate = (1.0*current_syns)/elapsed_time;
125     }
126 
127 
128     /*
129      * Print the message to <stderr> so that <stdout> can be redirected
130      * to a file (<stdout> reports what systems were found).
131      */
132     if (status->is_infinite) {
133         fprintf(stderr,
134                 "rate:%6.2f-kpps, syn/s=%.0f ack/s=%.0f tcb-rate=%.0f, %" PRIu64 "-tcbs,         \r",
135                         x/1000.0,
136                         syn_rate,
137                         synack_rate,
138                         tcb_rate,
139                         total_tcbs
140                         );
141     } else {
142         if (is_tx_done) {
143 
144             fprintf(stderr,
145                         "rate:%6.2f-kpps, %5.2f%% done, waiting %d-secs, found=%" PRIu64 "       \r",
146                         x/1000.0,
147                         percent_done,
148                         (int)exiting,
149                         total_synacks
150                        );
151 
152         } else {
153             fprintf(stderr,
154                 "rate:%6.2f-kpps, %5.2f%% done,%4u:%02u:%02u remaining, found=%" PRIu64 "       \r",
155                         x/1000.0,
156                         percent_done,
157                         (unsigned)(time_remaining/60/60),
158                         (unsigned)(time_remaining/60)%60,
159                         (unsigned)(time_remaining)%60,
160                         total_synacks
161                        );
162         }
163     }
164     fflush(stderr);
165 
166     /*
167      * Remember the values to be diffed against the next time around
168      */
169     status->last.clock = now;
170     status->last.count = count;
171 }
172 
173 /***************************************************************************
174  ***************************************************************************/
175 void
status_finish(struct Status * status)176 status_finish(struct Status *status)
177 {
178     UNUSEDPARM(status);
179     fprintf(stderr,
180 "                                                                             \r");
181 }
182 
183 /***************************************************************************
184  ***************************************************************************/
185 void
status_start(struct Status * status)186 status_start(struct Status *status)
187 {
188     memset(status, 0, sizeof(*status));
189     status->last.clock = clock();
190     status->last.time = time(0);
191     status->last.count = 0;
192     status->timer = 0x1;
193 }
194