/*
* ratedsource.{cc,hh} -- generates configurable rated stream of packets.
* Benjie Chen, Eddie Kohler (based on udpgen.o)
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include "ratedsource.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/router.hh>
#include <click/standard/scheduleinfo.hh>
#include <click/glue.hh>
CLICK_DECLS
const unsigned RatedSource::NO_LIMIT;
RatedSource::RatedSource()
: _packet(0), _task(this)
{
}
RatedSource::~RatedSource()
{
}
int
RatedSource::configure(Vector<String> &conf, ErrorHandler *errh)
{
String data =
"Random bullshit in a packet, at least 64 bytes long. Well, now it is.";
unsigned rate = 10;
int limit = -1;
int datasize = -1;
bool active = true, stop = false;
if (cp_va_parse(conf, this, errh,
cpOptional,
cpString, "packet data", &data,
cpUnsigned, "sending rate (packets/s)", &rate,
cpInteger, "total packet count", &limit,
cpBool, "active?", &active,
cpKeywords,
"DATA", cpString, "packet data", &data,
"DATASIZE", cpInteger, "minimum packet size", &datasize,
"RATE", cpUnsigned, "sending rate (packets/s)", &rate,
"LIMIT", cpInteger, "total packet count", &limit,
"ACTIVE", cpBool, "active?", &active,
"STOP", cpBool, "stop driver when done?", &stop,
cpEnd) < 0)
return -1;
_data = data;
_datasize = datasize;
_rate.set_rate(rate, errh);
_limit = (limit >= 0 ? limit : NO_LIMIT);
_active = active;
_stop = stop;
setup_packet();
return 0;
}
int
RatedSource::initialize(ErrorHandler *errh)
{
_count = 0;
if (output_is_push(0))
ScheduleInfo::initialize_task(this, &_task, errh);
return 0;
}
void
RatedSource::cleanup(CleanupStage)
{
if (_packet)
_packet->kill();
_packet = 0;
}
bool
RatedSource::run_task()
{
if (!_active)
return false;
if (_limit != NO_LIMIT && _count >= _limit) {
if (_stop)
router()->please_stop_driver();
return false;
}
Timestamp now = Timestamp::now();
if (_rate.need_update(now)) {
_rate.update();
Packet *p = _packet->clone();
p->set_timestamp_anno(now);
output(0).push(p);
_count++;
_task.fast_reschedule();
return true;
} else {
_task.fast_reschedule();
return false;
}
}
Packet *
RatedSource::pull(int)
{
if (!_active)
return 0;
if (_limit != NO_LIMIT && _count >= _limit) {
if (_stop)
router()->please_stop_driver();
return 0;
}
Timestamp now = Timestamp::now();
if (_rate.need_update(now)) {
_rate.update();
_count++;
Packet *p = _packet->clone();
p->set_timestamp_anno(now);
return p;
} else
return 0;
}
void
RatedSource::setup_packet()
{
if (_packet)
_packet->kill();
// note: if you change `headroom', change `click-align'
unsigned int headroom = 16+20+24;
if (_datasize != -1 && _datasize > _data.length()) {
// make up some data to fill extra space
String new_data;
do {
new_data += _data;
} while (new_data.length() < _datasize);
_packet = Packet::make(headroom, (unsigned char *) new_data.data(), _datasize, 0);
} else
_packet = Packet::make(headroom, (unsigned char *) _data.data(), _data.length(), 0);
}
String
RatedSource::read_param(Element *e, void *vparam)
{
RatedSource *rs = (RatedSource *)e;
switch ((intptr_t)vparam) {
case 0: // data
return rs->_data;
case 1: // rate
return String(rs->_rate.rate());
case 2: // limit
return (rs->_limit != NO_LIMIT ? String(rs->_limit) : String("-1"));
case 3: // active
return cp_unparse_bool(rs->_active);
case 4: // count
return String(rs->_count);
case 6: // datasize
return String(rs->_datasize);
default:
return "";
}
}
int
RatedSource::change_param(const String &in_s, Element *e, void *vparam,
ErrorHandler *errh)
{
RatedSource *rs = (RatedSource *)e;
String s = cp_uncomment(in_s);
switch ((intptr_t)vparam) {
case 0: // data
rs->_data = in_s;
if (rs->_packet)
rs->_packet->kill();
rs->_packet = Packet::make(rs->_data.data(), rs->_data.length());
break;
case 1: { // rate
unsigned rate;
if (!cp_unsigned(s, &rate))
return errh->error("rate parameter must be integer >= 0");
if (rate > GapRate::MAX_RATE)
// report error rather than pin to max
return errh->error("rate too large; max is %u", GapRate::MAX_RATE);
rs->_rate.set_rate(rate);
break;
}
case 2: { // limit
int limit;
if (!cp_integer(s, &limit))
return errh->error("limit parameter must be integer");
rs->_limit = (limit < 0 ? NO_LIMIT : limit);
break;
}
case 3: { // active
bool active;
if (!cp_bool(s, &active))
return errh->error("active parameter must be boolean");
rs->_active = active;
if (rs->output_is_push(0) && !rs->_task.scheduled() && active) {
rs->_rate.reset();
rs->_task.reschedule();
}
break;
}
case 5: { // reset
rs->_count = 0;
rs->_rate.reset();
if (rs->output_is_push(0) && !rs->_task.scheduled() && rs->_active)
rs->_task.reschedule();
break;
}
case 6: { // datasize
int datasize;
if (!cp_integer(s, &datasize) || datasize < 1)
return errh->error("datasize parameter must be integer >= 1");
rs->_datasize = datasize;
rs->setup_packet();
break;
}
}
return 0;
}
void
RatedSource::add_handlers()
{
add_read_handler("data", read_param, (void *)0);
add_write_handler("data", change_param, (void *)0);
set_handler_flags("data", Handler::RAW);
add_read_handler("rate", read_param, (void *)1);
add_write_handler("rate", change_param, (void *)1);
add_read_handler("limit", read_param, (void *)2);
add_write_handler("limit", change_param, (void *)2);
add_read_handler("active", read_param, (void *)3);
add_write_handler("active", change_param, (void *)3);
add_read_handler("count", read_param, (void *)4);
add_write_handler("reset", change_param, (void *)5);
add_read_handler("datasize", read_param, (void *)6);
add_write_handler("datasize", change_param, (void *)6);
if (output_is_push(0))
add_task_handlers(&_task);
}
CLICK_ENDDECLS
EXPORT_ELEMENT(RatedSource)
syntax highlighted by Code2HTML, v. 0.9.1