⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linktester.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
/* * linktester.{cc,hh} -- probe wireless links * Douglas S. J. De Couto * * Copyright (c) 2002 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 <fcntl.h>#include <click/config.h>#include <click/confparse.hh>#include "linktester.hh"#include <click/glue.hh>#include <clicknet/ether.h>#include <click/error.hh>#include <click/router.hh>#include "timeutils.hh"#include <unistd.h>CLICK_DECLSLinkTester::LinkTester() :  _start_time(-1),  _timer(static_timer_hook, this),   _curr_state(WAITING_TO_START),  _iterations_done(0),  _num_iters(1),  _pad(10000),  _packet_size(sizeof(click_ether) + sizeof(payload_t)),  _send_time(10000),  _lambda(1),  _bcast_packet_size(sizeof(click_ether) + sizeof(payload_t)),  _bcast_send_time(10000),  _bcast_lambda(1),  _data_buf(0){  add_output();}LinkTester::~LinkTester(){  if (_data_buf)    delete[] _data_buf;}intLinkTester::configure(Vector<String> &conf, ErrorHandler *errh){  int res = cp_va_parse(conf, this, errh,			cpEthernetAddress, "source ethernet address", &_src_eth,			cpEthernetAddress, "destination ethernet address", &_dst_eth,			cpKeywords,			"START_TIME", cpInteger, "start time (unix time_t)", &_start_time,			"ITERATIONS", cpUnsigned, "number of iterations", &_num_iters,			"SEND_FIRST", cpBool, "send first?", &_send_first,			"PAD_TIME", cpUnsigned, "milliseconds between each phase", &_pad,			"UNICAST_SEND_TIME", cpUnsigned, "time to send unicast backets (milliseconds)", &_send_time,			"BROADCAST_SEND_TIME", cpUnsigned, "time to send broadcast backets (milliseconds)", &_bcast_send_time,			"UNICAST_PACKET_SZ", cpUnsigned, "total size of unicast backets (bytes)", &_packet_size,			"BROADCAST_PACKET_SZ", cpUnsigned, "total size of broadcast backets (bytes)", &_bcast_packet_size,			"UNICAST_LAMBDA", cpDouble, "unicast inter-packet spacing lambda parameter", &_lambda,			"BROADCAST_LAMBDA", cpDouble, "broadcast inter-packet spacing lambda parameter", &_bcast_lambda,			cpEnd);  if (res > -1 && experiment_params_ok(errh))    return 1;  else    return -1;}// check consistency and viability of user-supplied parametersboolLinkTester::experiment_params_ok(ErrorHandler *errh){  if (_packet_size < sizeof(click_ether) + sizeof(payload_t)) {    errh->error("Unicast packets too small for ether header and sequence numbers");    return false;  }  if (_bcast_packet_size < sizeof(click_ether) + sizeof(payload_t)) {    errh->error("Broadcast packets too small for ether header and sequence numbers");    return false;  }  return true;}intLinkTester::initialize(ErrorHandler *errh){  unsigned int biggest = _packet_size > _bcast_packet_size ?    _packet_size : _bcast_packet_size;  unsigned int data_sz = biggest - sizeof(click_ether) - sizeof(payload_t);  _data_buf = new unsigned char[data_sz];  if (!_data_buf)    return errh->error("Unable to allocate data buffer");  for (unsigned int i = 0; i < data_sz; i++)    _data_buf[i] = i % 256;  bool res = init_random();  if (!res)    return errh->error("Unable to initialize random number generator");  Timestamp now = Timestamp::now();  if (_start_time < 0) // start ``immediately''    _start_time = now.sec() + 5;  if (now.sec() >= (int) _start_time)    return errh->error("Start time %u has alread passed", _start_time);  _timer.initialize(this);  _start_time_tv = Timestamp(_start_time, 0);  _timer.schedule_at(_start_time_tv);  _last_time = now;  _next_time = _start_time_tv;  return 0;}voidLinkTester::timer_hook(){  Timestamp tv = Timestamp::now();#if 1  click_chatter("OK %{timestamp}    (delta: %s)\n", tv.unparse().cc(),		(tv - _last_time).unparse().cc());#endif  _last_time = tv;  switch (_curr_state) {  case WAITING_TO_START: handle_timer_waiting(tv); break;  case LISTENING: handle_timer_listening(tv); break;  case BCAST_1: handle_timer_bcast(tv); break;  case UNICAST: handle_timer_unicast(tv); break;  case BCAST_2: handle_timer_bcast(tv); break;  case DONE:  default:    assert(0);  }}void LinkTester::handle_timer_waiting(const Timestamp &tv){  assert(_curr_state == WAITING_TO_START);  _iterations_done = 0;  if (_num_iters == 0) {    finish_experiment();    return;  }  if (_send_first) {    _curr_state = BCAST_1;    _bcast_packets_sent = 0;    handle_timer_bcast(tv);  }  else {    _curr_state = LISTENING;    int listen_for = calc_listen_time() + calc_pad_time();    _next_time = _start_time_tv + Timestamp::make_msec(listen_for);        assert(_next_time > tv);    _timer.schedule_at(_next_time);  }}void LinkTester::handle_timer_listening(const Timestamp &tv){  assert(_curr_state == LISTENING);  // check for end of experiment  if (_send_first) {    _iterations_done++;    if (_iterations_done >= _num_iters) {      finish_experiment();      return;    }  }  _curr_state = BCAST_1;  _bcast_packets_sent = 0;  handle_timer_bcast(tv);}void LinkTester::handle_timer_bcast(const Timestamp &tv){  assert(_curr_state == BCAST_1 || _curr_state == BCAST_2);  send_broadcast_packet((unsigned short) _bcast_packet_size, tv, 			_curr_state == BCAST_1, _bcast_packets_sent, 			_iterations_done);  _bcast_packets_sent++;  // when would we like to send the next bcast packet?  unsigned int delta = draw_random_msecs(_bcast_lambda);  Timestamp new_next_time = _next_time + Timestamp::make_msec(delta);    // is there enough time left to send the next packet?  if (new_next_time <= last_bcast_time(_iterations_done,				       _curr_state == BCAST_1)) {    _next_time = new_next_time;  }  else {    // switch to the next phase    if (_curr_state == BCAST_1) {      _curr_state = UNICAST;      _packets_sent = 0;      _next_time = first_unicast_time(_iterations_done);    }    else {      assert(_curr_state == BCAST_2);      // we just completed the second set of broadcasts.  possible      // outcomes are:      // 1. listen at the end of this iteration      // 2. listen at the beginning of the next iteration      // 3. quit, experiment over...      if (_send_first) {	_curr_state = LISTENING;	_next_time = first_bcast_time(_iterations_done + 1, true);      }      else {	_iterations_done++;	if (_iterations_done >= _num_iters) {	  finish_experiment();	  	  return;	}	else {	  _curr_state = LISTENING;	  _next_time = first_bcast_time(_iterations_done, true);	}      }    }  }  assert(_next_time > tv);  _timer.schedule_at(_next_time);  return;    } void LinkTester::handle_timer_unicast(const Timestamp &tv){  assert(_curr_state == UNICAST);  send_unicast_packet(tv, _packets_sent, _iterations_done);  _packets_sent++;  unsigned int delta = draw_random_msecs(_lambda);  Timestamp new_next_time = _next_time + Timestamp::make_msec(delta);  // is there enough time left to sent the next packet?  if (new_next_time <= last_unicast_time(_iterations_done))    _next_time = new_next_time;  else {    // switch to next phase    _curr_state = BCAST_2;    _bcast_packets_sent = 0;    _next_time = first_bcast_time(_iterations_done, false);  }  assert(_next_time > tv);  _timer.schedule_at(_next_time);}unsigned intLinkTester::calc_listen_time() {  return calc_bcast_time() + calc_pad_time() + calc_unicast_time()     + calc_pad_time() + calc_bcast_time();}unsigned intLinkTester::calc_unicast_time(){  return _send_time;}unsigned intLinkTester::calc_bcast_time(){  return _bcast_send_time;}TimestampLinkTester::first_unicast_time(unsigned int iter){  unsigned int iter_time = 2 * (calc_listen_time() + calc_pad_time());  unsigned int delta = iter_time * iter;  delta += calc_bcast_time() + calc_pad_time();  if (!_send_first) // let other node send first    delta += calc_listen_time() + calc_pad_time();  return Timestamp::make_msec(delta) + _start_time_tv;}TimestampLinkTester::first_bcast_time(unsigned int iter, bool before){  unsigned int iter_time = 2 * (calc_listen_time() + calc_pad_time());  unsigned int delta = iter_time * iter;  if (!_send_first) // let other node send first    delta += calc_listen_time() + calc_pad_time();  if (!before)    delta += calc_bcast_time() + calc_pad_time() + calc_unicast_time() + calc_pad_time();  return Timestamp::make_msec(delta) + _start_time_tv;}TimestampLinkTester::last_unicast_time(unsigned int iter){  return first_unicast_time(iter) + Timestamp::make_msec(calc_unicast_time());}TimestampLinkTester::last_bcast_time(unsigned int iter, bool before){  return first_bcast_time(iter, before) + Timestamp::make_msec(calc_bcast_time());}voidLinkTester::send_unicast_packet(const Timestamp &tv,				unsigned int seq, unsigned int iter){  WritablePacket *p = Packet::make(_packet_size);  click_ether *eh = (click_ether *) (p->data());  memcpy(eh->ether_dhost, _dst_eth.data(), 6);  memcpy(eh->ether_shost, _src_eth.data(), 6);  eh->ether_type = htons(ETHERTYPE);  payload_t *payload = (payload_t *) (eh + 1);  memset(payload, 0, sizeof(payload_t));  payload->size = htons(_packet_size);  payload->iteration = htonl(iter);  payload->seq_no = htonl(seq);  payload->tx_sec = htonl(tv.sec());  payload->tx_usec = htonl(tv.usec());  unsigned int data_sz = _packet_size - sizeof(click_ether) - sizeof(payload_t);  if (data_sz > 0)    memcpy(p->data() + sizeof(click_ether) + sizeof(payload_t), 	   _data_buf, data_sz);  output(0).push(p);}voidLinkTester::send_broadcast_packet(unsigned short psz, const Timestamp &tv,				  bool before, unsigned int seq, unsigned int iter){  assert(psz >= sizeof(click_ether) + sizeof(payload_t));  WritablePacket *p = Packet::make(psz);  click_ether *eh = (click_ether *) (p->data());    static unsigned char bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };  memcpy(eh->ether_dhost, bcast_addr, 6);  memcpy(eh->ether_shost, _src_eth.data(), 6);  eh->ether_type = htons(ETHERTYPE);  payload_t *payload = (payload_t *) (eh + 1);  memset(payload, 0, sizeof(payload_t));  payload->size = htons(psz);  payload->before = before ? 1 : 0;  payload->iteration = htonl(iter);  payload->seq_no = htonl(seq);  payload->tx_sec = htonl(tv.sec());  payload->tx_usec = htonl(tv.usec());  unsigned int data_sz = psz - sizeof(click_ether) - sizeof(payload_t);  if (data_sz > 0)    memcpy(p->data() + sizeof(click_ether) + sizeof(payload_t), 	   _data_buf, data_sz);  output(0).push(p);}voidLinkTester::finish_experiment() {  click_chatter("DONE\n");  router()->please_stop_driver();}boolLinkTester::init_random(){  int fd = open("/dev/urandom", O_RDONLY);  if (fd == -1)    return false;    unsigned long seed;  int err = read(fd, &seed, sizeof(seed));  if (err != sizeof(seed))    return false;    close(fd);  srandom(seed);  return true;}doubleLinkTester::draw_random(double lambda){  // draw an exponentially distributed variable with parameter lambda#if 0  double r = (double) random() / (double) RAND_MAX;  return -lambda * log(r);#else  lambda = 0;  return 100;#endif}EXPORT_ELEMENT(LinkTester)ELEMENT_REQUIRES(userlevel)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -