diff --git a/scan_engine.cc b/scan_engine.cc index 85ae63c11..b2faacede 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -643,7 +643,7 @@ public: list completedHosts; ScanProgressMeter *SPM; - RateMeter send_rate_meter; + PacketRateMeter send_rate_meter; struct scan_lists *ports; int rawsd; /* raw socket descriptor */ pcap_t *pd; @@ -2693,7 +2693,7 @@ static UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss, PacketTrace::traceConnect(IPPROTO_TCP, (sockaddr *) &sock, socklen, rc, connect_errno, &USI->now); /* We don't record a byte count for connect probes. */ - USI->send_rate_meter.record(0, &USI->now); + USI->send_rate_meter.update(0, &USI->now); /* This counts as probe being sent, so update structures */ hss->probes_outstanding.push_back(probe); probeI = hss->probes_outstanding.end(); @@ -2791,7 +2791,7 @@ static UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss, error("WARNING: eth_send of ARP packet returned %i rather than expected %d (errno=%i: %s)", rc, (int) sizeof(frame), err, strerror(err)); } PacketTrace::traceArp(PacketTrace::SENT, (u8 *) frame, sizeof(frame), &USI->now); - USI->send_rate_meter.record(sizeof(frame), &USI->now); + USI->send_rate_meter.update(sizeof(frame), &USI->now); probe->tryno = tryno; probe->pingseq = pingseq; /* First build the probe */ @@ -2969,7 +2969,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, free(packet); } } else assert(0); /* TODO: Maybe RPC scan and the like */ - USI->send_rate_meter.record(packetlen, &USI->now); + USI->send_rate_meter.update(packetlen, &USI->now); /* Now that the probe has been sent, add it to the Queue for this host */ hss->probes_outstanding.push_back(probe); USI->gstats->num_probes_active++; diff --git a/timing.cc b/timing.cc index b0527f7b3..21ca218e9 100644 --- a/timing.cc +++ b/timing.cc @@ -238,19 +238,18 @@ void enforce_scan_delay(struct timeval *tv) { return; } -/* Initialize the constant CURRENT_RATE_HISTORY that defines how far back we - look when calculating the current rates. */ -RateMeter::RateMeter() : CURRENT_RATE_HISTORY(5.0) { +/* current_rate_history defines how far back (in seconds) we look when + calculating the current rate. */ +RateMeter::RateMeter(double current_rate_history) { + this->current_rate_history = current_rate_history; start_tv.tv_sec = 0; start_tv.tv_usec = 0; stop_tv.tv_sec = 0; stop_tv.tv_usec = 0; last_update_tv.tv_sec = 0; last_update_tv.tv_usec = 0; - num_packets = 0; - num_bytes = 0; - current_packet_rate = 0.0; - current_byte_rate = 0.0; + total = 0.0; + current_rate = 0.0; assert(!isSet(&start_tv)); assert(!isSet(&stop_tv)); } @@ -273,52 +272,9 @@ void RateMeter::stop(const struct timeval *now) { stop_tv = *now; } -/* Record a packet of length len. If now is not NULL, use it as the time the - packet was received rather than calling gettimeofday. */ -void RateMeter::record(u32 len, const struct timeval *now) { - update(1, len, now); -} - -double RateMeter::getOverallPacketRate(const struct timeval *now) const { - return num_packets / elapsedTime(now); -} - -/* Get the "current" packet rate (actually a moving average of the last few - seconds). If update is true (its default value), lower the rate to account - for the time since the last packet was received. */ -double RateMeter::getCurrentPacketRate(const struct timeval *now, bool update) { - if (update) - this->update(0, 0, now); - - return current_packet_rate; -} - -double RateMeter::getOverallByteRate(const struct timeval *now) const { - return num_bytes / elapsedTime(now); -} - -/* Get the "current" byte rate (actually a moving average of the last few - seconds). If update is true (its default value), lower the rate to account - for the time since the last bytes were received. */ -double RateMeter::getCurrentByteRate(const struct timeval *now, bool update) { - if (update) - this->update(0, 0, now); - - return current_byte_rate; -} - -unsigned long long RateMeter::getNumPackets(void) const { - return num_packets; -} - -unsigned long long RateMeter::getNumBytes(void) const { - return num_bytes; -} - -/* Update the rates to include packets additional packets and bytes additional - bytes. If now is not NULL, use it as the time the packets and bytes were - received rather than calling gettimeofday. */ -void RateMeter::update(u32 packets, u32 bytes, const struct timeval *now) { +/* Update the rates to reflect the given amount added to the total at the time + now. If now is NULL, get the current time with gettimeofday. */ +void RateMeter::update(double amount, const struct timeval *now) { struct timeval tv; static int clockwarn = 0; double diff; @@ -328,9 +284,8 @@ void RateMeter::update(u32 packets, u32 bytes, const struct timeval *now) { assert(isSet(&start_tv)); assert(!isSet(&stop_tv)); - /* Update the overall counters. */ - num_packets += packets; - num_bytes += bytes; + /* Update the total. */ + total += amount; if (now == NULL) { gettimeofday(&tv, NULL); @@ -339,9 +294,9 @@ void RateMeter::update(u32 packets, u32 bytes, const struct timeval *now) { if (!isSet(&last_update_tv)) last_update_tv = start_tv; - /* Calculate approximate moving averages of how many packets and bytes were - recorded in the last CURRENT_RATE_HISTORY seconds. These averages are what - are returned as the "current" rates. */ + /* Calculate the approximate moving average of how much was recorded in the + last current_rate_history seconds. This average is what is returned as the + "current" rate. */ /* How long since the last update? */ diff = TIMEVAL_SUBTRACT(*now, last_update_tv) / 1000000.0; @@ -365,40 +320,53 @@ void RateMeter::update(u32 packets, u32 bytes, const struct timeval *now) { fatal("RateMeter::update: negative time delta; now=%lu.%lu; last_update_tv=%lu.%lu", (unsigned long) now->tv_sec, (unsigned long) now->tv_usec, (unsigned long) last_update_tv.tv_sec, (unsigned long) last_update_tv.tv_usec); /* Find out how far back in time to look. We want to look back - CURRENT_RATE_HISTORY seconds, or to when the last update occurred, + current_rate_history seconds, or to when the last update occurred, whichever is longer. However, we never look past the start. */ struct timeval tmp; - /* Find the time CURRENT_RATE_HISTORY seconds after the start. That's our + /* Find the time current_rate_history seconds after the start. That's our threshold for deciding how far back to look. */ - TIMEVAL_ADD(tmp, start_tv, (time_t) (CURRENT_RATE_HISTORY * 1000000.0)); + TIMEVAL_ADD(tmp, start_tv, (time_t) (current_rate_history * 1000000.0)); if (TIMEVAL_AFTER(*now, tmp)) - interval = MAX(CURRENT_RATE_HISTORY, diff); + interval = MAX(current_rate_history, diff); else interval = TIMEVAL_SUBTRACT(*now, start_tv) / 1000000.0; assert(diff <= interval); - /* If we get packets in the very same instant that the timer is started, + /* If we record an amount in the very same instant that the timer is started, there's no way to calculate meaningful rates. Ignore it. */ if (interval == 0.0) return; - /* To calculate the approximate average of the packet rate over the last + /* To calculate the approximate average of the rate over the last interval seconds, we assume that the rate was constant over that interval. - We calculate how many packets would have been received in that interval, - ignoring the first diff seconds' worth: - (interval - diff) * current_packet_rate. - Then we add how many packets were received in the most recent diff seconds. - Divide by the width of the interval to get the average. */ - count = (interval - diff) * current_packet_rate + packets; - current_packet_rate = count / interval; - assert(current_packet_rate >= 0.0); - /* Likewise with the byte rate. */ - count = (interval - diff) * current_byte_rate + bytes; - current_byte_rate = count / interval; - assert(current_byte_rate >= 0.0); + We calculate how much would have been received in that interval, ignoring + the first diff seconds' worth: + (interval - diff) * current_rate. + Then we add how much was received in the most recent diff seconds. Divide + by the width of the interval to get the average. */ + count = (interval - diff) * current_rate + amount; + current_rate = count / interval; last_update_tv = *now; } +double RateMeter::getOverallRate(const struct timeval *now) const { + return total / elapsedTime(now); +} + +/* Get the "current" rate (actually a moving average of the last + current_rate_history seconds). If update is true (its default value), lower + the rate to account for the time since the last record. */ +double RateMeter::getCurrentRate(const struct timeval *now, bool update) { + if (update) + this->update(0.0, now); + + return current_rate; +} + +double RateMeter::getTotal(void) const { + return total; +} + /* Get the number of seconds the meter has been running: if it has been stopped, the amount of time between start and stop, or if it is still running, the amount of time between start and now. */ @@ -426,6 +394,51 @@ bool RateMeter::isSet(const struct timeval *tv) { return tv->tv_sec != 0 || tv->tv_usec != 0; } +PacketRateMeter::PacketRateMeter(double current_rate_history) { + packet_rate_meter = RateMeter(current_rate_history); + byte_rate_meter = RateMeter(current_rate_history); +} + +void PacketRateMeter::start(const struct timeval *now) { + packet_rate_meter.start(now); + byte_rate_meter.start(now); +} + +void PacketRateMeter::stop(const struct timeval *now) { + packet_rate_meter.stop(now); + byte_rate_meter.stop(now); +} + +/* Record one packet of length len. */ +void PacketRateMeter::update(u32 len, const struct timeval *now) { + packet_rate_meter.update(1, now); + byte_rate_meter.update(len, now); +} + +double PacketRateMeter::getOverallPacketRate(const struct timeval *now) const { + return packet_rate_meter.getOverallRate(now); +} + +double PacketRateMeter::getCurrentPacketRate(const struct timeval *now, bool update) { + return packet_rate_meter.getCurrentRate(now, update); +} + +double PacketRateMeter::getOverallByteRate(const struct timeval *now) const { + return byte_rate_meter.getOverallRate(now); +} + +double PacketRateMeter::getCurrentByteRate(const struct timeval *now, bool update) { + return byte_rate_meter.getCurrentRate(now, update); +} + +unsigned long long PacketRateMeter::getNumPackets(void) const { + return (unsigned long long) packet_rate_meter.getTotal(); +} + +unsigned long long PacketRateMeter::getNumBytes(void) const { + return (unsigned long long) byte_rate_meter.getTotal(); +} + ScanProgressMeter::ScanProgressMeter(const char *stypestr) { scantypestr = strdup(stypestr); gettimeofday(&begin, NULL); diff --git a/timing.h b/timing.h index f79cd2716..2f6a743c5 100644 --- a/timing.h +++ b/timing.h @@ -123,31 +123,28 @@ void adjust_timeouts2(const struct timeval *sent, response. We update our RTT averages, etc. */ void adjust_timeouts(struct timeval sent, struct timeout_info *to); +#define DEFAULT_CURRENT_RATE_HISTORY 5.0 /* Sleeps if necessary to ensure that it isn't called twice within less time than o.send_delay. If it is passed a non-null tv, the POST-SLEEP time is recorded in it */ void enforce_scan_delay(struct timeval *tv); -/* This class implements current and lifetime average data rates for packets and - bytes. */ +/* This class measures current and lifetime average rates for some quantity. */ class RateMeter { public: - RateMeter(); + RateMeter(double current_rate_history = DEFAULT_CURRENT_RATE_HISTORY); void start(const struct timeval *now = NULL); void stop(const struct timeval *now = NULL); - void record(u32 len, const struct timeval *now = NULL); - double getOverallPacketRate(const struct timeval *now = NULL) const; - double getCurrentPacketRate(const struct timeval *now = NULL, bool update =true); - double getOverallByteRate(const struct timeval *now = NULL) const; - double getCurrentByteRate(const struct timeval *now = NULL, bool update =true); - unsigned long long getNumPackets(void) const; - unsigned long long getNumBytes(void) const; + void update(double amount, const struct timeval *now = NULL); + double getOverallRate(const struct timeval *now = NULL) const; + double getCurrentRate(const struct timeval *now = NULL, bool update = true); + double getTotal(void) const; private: /* How many seconds to look back when calculating the "current" rates. */ - const double CURRENT_RATE_HISTORY; + double current_rate_history; /* When this meter started recording. */ struct timeval start_tv; @@ -156,17 +153,33 @@ class RateMeter { /* The last time the current sample rates were updated. */ struct timeval last_update_tv; - unsigned long long num_packets; - unsigned long long num_bytes; + double total; + double current_rate; - double current_packet_rate; - double current_byte_rate; - - void update(u32 packets, u32 bytes, const struct timeval *now); double elapsedTime(const struct timeval *now = NULL) const; static bool isSet(const struct timeval *tv); }; +/* A specialization of RateMeter that measures packet and byte rates. */ +class PacketRateMeter { + public: + PacketRateMeter(double current_rate_history = DEFAULT_CURRENT_RATE_HISTORY); + + void start(const struct timeval *now = NULL); + void stop(const struct timeval *now = NULL); + void update(u32 len, const struct timeval *now = NULL); + double getOverallPacketRate(const struct timeval *now = NULL) const; + double getCurrentPacketRate(const struct timeval *now = NULL, bool update = true); + double getOverallByteRate(const struct timeval *now = NULL) const; + double getCurrentByteRate(const struct timeval *now = NULL, bool update =true); + unsigned long long getNumPackets(void) const; + unsigned long long getNumBytes(void) const; + + private: + RateMeter packet_rate_meter; + RateMeter byte_rate_meter; +}; + class ScanProgressMeter { public: /* A COPY of stypestr is made and saved for when stats are printed */