/* doscan - Denial Of Service Capable Auditing of Networks       -*- C++ -*-
 * Copyright (C) 2003 Florian Weimer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"
#include "opt.h"
#include "results.h"
#include "scan_trigger.h"
#include "subnets.h"

#include <cstdio>

// trigger_handler

scan_trigger::trigger_handler::trigger_handler(event_queue& q,
                                               subnets& n,
                                               scan_trigger& t,
                                               scan_trigger::handler& h,
                                               unsigned max, unsigned delay,
                                               unsigned size)
  : handler(q), nets(n), trigger(t), connect_handler(h),
    count(0), maximum(max), burst_delay(delay), burst_size(size),
    last_indicator(ticks_get_cached())
{
  set_immediate_timeout();
}

bool
scan_trigger::trigger_handler::on_timeout(ticks_t)
{
  if (opt_indicator && ticks_get_cached() > (last_indicator + 500)) {
    last_indicator = ticks_get_cached();
    fprintf (stderr, "%u of %u connected, %u active, %u reported     \r",
             nets.hosts_processed(), nets.hosts_total(),
             count, results_count());
    fflush (stderr);
  }

  unsigned to_add = maximum - count;
  if (to_add > burst_size) {
    to_add = burst_size;
  }

  for (unsigned j = 0; j < to_add; ++j) {
    if (nets.finished()) {
      if (count != 0) {
        // Wait for pending terminations.
        if (opt_indicator) {
          set_relative_timeout(1000);
        } else {
          set_infinite_timeout();
        }
        return true;
      } else {
        // All connections have been terminated.
        if (opt_indicator) {
          fprintf (stderr, "%u of %u connected, %u active, %u reported     \n",
                   nets.hosts_processed(), nets.hosts_total(),
                   count, results_count());
          fflush (stderr);
        }
        connect_handler.all_connected();
        return false;
      }
    }

    ++count;
    connect_handler.connect(queue(), trigger, nets.next());
  }

  set_relative_timeout(burst_delay);
  return true;
}

void
scan_trigger::trigger_handler::finish()
{
  if (count == 0) {
    abort();
  }
  --count;
  if (count == 0) {
    set_immediate_timeout();
  }
}


// handler

scan_trigger::handler::~handler()
{
}

void
scan_trigger::handler::all_connected()
{
}

// scan_trigger

scan_trigger::scan_trigger(event_queue& q, subnets& n, handler& h,
                           unsigned maximum, unsigned burst_delay ,
                           unsigned burst_size)
{
  trigger = new trigger_handler(q, n, *this, h,
                                maximum, burst_delay, burst_size);
}
