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

📄 snooptcp.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* * snooptcp.{cc,hh} -- element implements Snoop TCP a la Balakrishnan * Alex Snoeren, Eddie Kohler * * 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>#ifdef __linux__# define _BSD_SOURCE#endif#include "snooptcp.hh"#include <click/ipaddress.hh>#include <click/confparse.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/bitvector.hh>#ifdef DEBUG# define DEBUG_CHATTER(args...) click_chatter(args)#else# define DEBUG_CHATTER(args...) /* nothing */#endifCLICK_DECLSSnoopTCP::SnoopTCP()  : Element(2, 4){}SnoopTCP::~SnoopTCP(){}intSnoopTCP::initialize(ErrorHandler *errh){  return errh->error("SnoopTCP is not ready to use");}inline voidSnoopTCP::SCacheEntry::clear(){  assert(packet);  packet->kill();  packet = 0;}SnoopTCP::PCB::PCB()  : _head(0), _tail(0), _s_exists(0), _s_alive(0), _mh_exists(0), _mh_alive(0){}SnoopTCP::PCB::~PCB(){  for (int i = _tail; i != _head; i = next_i(i))    _s_cache[i].packet->kill();}voidSnoopTCP::PCB::clear(bool is_s){  if (is_s && _s_exists) {    // XXX untimeout    for (int i = _tail; i != _head; i = next_i(i))      _s_cache[i].packet->kill();    _head = _tail = 0;    // XXX if (!_mh_alive) clear(false);    _s_exists = _s_alive = false;  } else if (!is_s && _mh_exists) {    _mh_exists = _mh_alive = false;  }  // XXX remove from hashtable}voidSnoopTCP::PCB::initialize(bool is_s, const click_tcp *tcph, int datalen){  unsigned seq = ntohl(tcph->th_seq);    if (is_s) {    assert(!_s_exists);    _s_exists = _s_alive = true;    //cs->alloc = 0;    _s_max = seq + datalen;	// replaces cs->last_seen    _mh_last_ack = seq - 1;    _mh_expected_dup_acks = 0;    _mh_dup_acks = 0;    //cs->iss = seq;         //cs->expected_next_ack = cs->buftail;    //if (tcpip_hdr->ti_flags & TH_ACK)    //cs->wl_last_ack = ack;    /*      * Ideally, this should be initialized to the rtt estimate      * from another connection to the same destination, if one      * exists. For now, choose an uninformed and conservative      * default.     */    //cs->srtt = SNOOP_RTTDEFAULT;    //cs->rttdev = SNOOP_RTTDEVDEFAULT;    //cs->timeout_pending = 0;  } else {    _mh_exists = _mh_alive = true;  }}voidSnoopTCP::PCB::clean(unsigned ack, struct timeval *last_cleaned_time){  //snoop_untimeout(cs);  timerclear(last_cleaned_time);    int i = _tail;  while (i != _head && SEQ_LEQ(_s_cache[i].seq + _s_cache[i].size, ack)) {    SCacheEntry &cache = _s_cache[i];    if (timercmp(&cache.snd_time, last_cleaned_time, >))      *last_cleaned_time = cache.snd_time;    cache.clear();    i = next_i(i);  }  _tail = i;    // if (_head != _tail) snoop_timeout(cs);}voidSnoopTCP::PCB::s_ack(Packet *, const click_tcp *, int){  // XXX rest}Packet *SnoopTCP::PCB::s_data(Packet *p, const click_tcp *tcph, int datalen){  // initialize if no connection (half-duplex, or Snoop came up in the middle  // of a connection). always mark the connection alive  if (!_s_exists)    initialize(true, tcph, datalen);  else    _s_alive = true;    bool full = next_i(_head) == _tail;  int entry = -1;  bool in_sequence = false;  bool repeat_packet = false;  unsigned seq = ntohl(tcph->th_seq);    // insert the packet into the cache  if (SEQ_GEQ(seq, _s_max)) {    // common case    // don't save packet if over high water mark    // (at that point cache is reserved for earlier packets)    if (s_cache_size() >= S_CACHE_HIGHWATER) return p;    _s_max = seq + datalen;    entry = _head;    _head = next_i(_head);    in_sequence = true;      } else {    for (int i = _tail; i != _head; i = next_i(i))      if (_s_cache[i].seq == seq) {	// a repeat packet	// always keep the repeat (Hari does). an alternative would be	// to keep the longer of the two	_s_cache[i].packet->kill();	repeat_packet = true;	entry = i;	break;	      } else if (SEQ_GT(_s_cache[i].seq, seq)) {	// out-of-order packet	if (full) return p;	// XXX memmove??	for (int j = _tail; j != i; j = next_i(j))	  _s_cache[prev_i(j)] = _s_cache[j];	entry = prev_i(i);	_tail = prev_i(_tail);	break;      }  }    // cache packet at `_cache[entry]'  assert(entry >= 0 && 0);  _s_cache[entry].packet = p->clone();  _s_cache[entry].seq = seq;  _s_cache[entry].num_rxmit = 0;  // mark as sender retransmission if it really was (we had cached the packet  // before), or it was before all cached packets  if (repeat_packet || (!in_sequence && entry == _tail))    _s_cache[entry].sender_rxmit = 1;  else    _s_cache[entry].sender_rxmit = 0;  click_gettimeofday(&_s_cache[entry].snd_time);  DEBUG_CHATTER("\t%d at %d\n", seq, entry);    // XXX if (!in_sequence) snoop_untimeout();  // XXX snoop_timeout();    return p;}voidSnoopTCP::PCB::mh_new_ack(unsigned ack){  int old_tail = -1;  if (_tail != _head && _s_cache[_tail].num_rxmit)    old_tail = _tail;    struct timeval last_cleaned_time;  clean(ack, &last_cleaned_time);    //if ((cs->wi_state & SNOOP_RTTFLAG) && timerisset(&sndtime))  //snoop_rtt(cs, &sndtime);    // check for burst loss  if (old_tail >= 0 && s_cache_size() > 1 && next_i(old_tail) == _tail      && _s_cache[_tail].num_rxmit == 0)    //snoop_rexmt_pkt(cs, packet,     //IPTOS_LOWDELAY|IPTOS_RELIABILITY|    //IPTOS_THROUGHPUT);    /* do nothing */;    //cs->wi_state |= SNOOP_RTTFLAG;  _mh_expected_dup_acks = 0;  _mh_dup_acks = 0;  _mh_last_ack = ack;}#define SNOOP_RTX_THRESH 1Packet *SnoopTCP::PCB::mh_dup_ack(Packet *p, const click_tcp *tcph, unsigned ack){  // if snoop cache empty, nothing to do  if (_head == _tail)    return p;    // window change advertisements are not semantically duplicate acks  if (_mh_last_win != ntohs(tcph->th_win))    return p;    // if we don't have the packet, nothing to do  SCacheEntry &cache = _s_cache[_tail];  if (SEQ_LT(ack, cache.seq))    return p;    // if sender retransmission, nothing to do  if (cache.sender_rxmit)    return p;    // otherwise, a duplicate ack we can handle  _mh_dup_acks++;    if (_mh_dup_acks <= SNOOP_RTX_THRESH) {    // ignore first SNOOP_RTX_THRESH duplicate acks    p->kill();    return 0;      } else if (_mh_dup_acks == SNOOP_RTX_THRESH + 1) {    // the SNOOP_RTX_THRESHth duplicate ack: calculate how many were    // expected, generate a retransmission    _mh_expected_dup_acks = s_cache_size() - _mh_dup_acks;    if (!cache.num_rxmit)      /*snoop_rexmt_pkt(cs, packet, IPTOS_LOWDELAY)*/;    p->kill();    return 0;      } else if (_mh_dup_acks < _mh_expected_dup_acks) {    // delete expected duplicate acks    p->kill();    return 0;      } else {    // too many duplicate acks; retransmit last packet once, then start    // letting duplicate acks pass through    // XXX COMPAT some changes here    if (cache.num_rxmit < 2) {      //snoop_rexmt_pkt(cs, packet, IPTOS_LOWDELAY|IPTOS_RELIABILITY|IPTOS_THROUGHPUT);      p->kill();      return 0;    } else      return p;  }}Packet *SnoopTCP::PCB::mh_ack(Packet *p, const click_tcp *tcph, int datalen){  // if server connection is dead, do nothing  if (!_s_exists)    return p;    unsigned ack = ntohl(tcph->th_ack);  if (SEQ_GT(ack, _mh_last_ack))    // new ack    mh_new_ack(ack);  

⌨️ 快捷键说明

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