官方淘宝店 易迪拓培训 旧站入口
首页 > 无线通信 > 通信技术学习讨论 > 求助!NS2中添加新的TCP Sink类后出错

求助!NS2中添加新的TCP Sink类后出错

12-16
我在已有的TCPSink.h, TCPSink.cc文件里面添加了一个新的TCPSink类,叫TCPNCSink,还在ns-defalut.tcl里面定义了关于这个类的缺省值,编译通过,但是写一段tcl文件运行一下,就出错:
invalid command name "Agent/TCPNCSink"
    while executing
"Agent/TCPNCSink create _o92 "
    invoked from within
"catch "$className create $o $args" msg"
    invoked from within
"if [catch "$className create $o $args" msg] {
if [string match "__FAILED_SHADOW_OBJECT_" $msg] {
delete $o
return ""
}
global errorInfo
error "class $..."
    (procedure "new" line 3)
    invoked from within
"new Agent/TCPNCSink"
    invoked from within
"set sink [new Agent/TCPNCSink]"
    (file "simple-nc.tcl" line 53)
用NS指导书里面列出所有Agent的子类那个proc运行一下,也没有显示出新建的这个TCPNCSink。
我是不是少做了点啥?
谢谢!

贴代码
贴代码

代码如下:
//tcp-sink-nc.h
#ifndef ns_tcpncsink_h
#define ns_tcpncsink_h
#include <math.h>
#include "agent.h"
#include "tcp.h"
/* max window size */
// #define MWS 1024  
#define MWS 64
#define MWM (MWS-1)
#define HS_MWS 65536
#define HS_MWM (MWS-1)
/* For Tahoe TCP, the "window" parameter, representing the receiver's
* advertised window, should be less than MWM.  For Reno TCP, the
* "window" parameter should be less than MWM/2.
*/
class TcpNCSink;
class NCAcker {
public:
    NCAcker();
    virtual ~NCAcker() { delete[] seen_; }
    void update_ts(int seqno, double ts, int rfc1323 = 0);
    int update(int seqno, int numBytes);
    void update_ecn_unacked(int value);
    inline int Seqno() const { return (next_ - 1); }
    virtual void append_ack(hdr_cmn*, hdr_tcp*, int oldSeqno) const;
    void reset();
    double ts_to_echo() { return ts_to_echo_;}
    int ecn_unacked() { return ecn_unacked_;}
    inline int Maxseen() const { return (maxseen_); }
    void resize_buffers(int sz);  // resize the seen_ buffer
protected:
    int next_;        /* next packet expected */
    int maxseen_;        /* max packet number seen */
    int wndmask_;        /* window mask - either MWM or HS_MWM - Sylvia */
    int ecn_unacked_;    /* ECN forwarded to sender, but not yet
                 * acknowledged. */
    int *seen_;        /* array of packets seen */
    double ts_to_echo_;    /* timestamp to echo to peer */
    int is_dup_;        // A duplicate packet.
public:
        int last_ack_sent_;     // For updating timestamps, from Andrei Gurtov.
};
// derive Sacker from TclObject to allow for traced variable
class NCSackStack;
class NCSacker : public NCAcker, public TclObject {
public:
    NCSacker() : base_nblocks_(-1), sf_(0) { };
    ~NCSacker();
    void append_ack(hdr_cmn*, hdr_tcp*, int oldSeqno) const;
    void reset();
    void configure(TcpNCSink*);
protected:
    int base_nblocks_;
    int* dsacks_;        // Generate DSACK blocks.
    NCSackStack *sf_;
    void trace(TracedVar*);
};
class TcpNCSink : public Agent {
    friend class XcpSink;
public:
    TcpNCSink(NCAcker*);
    void recv(Packet* pkt, Handler*);
    void reset();
    int command(int argc, const char*const* argv);
    TracedInt& maxsackblocks() { return max_sack_blocks_; }
protected:
    void ack(Packet*);
    virtual void add_to_ack(Packet* pkt);
        virtual void delay_bind_init_all();
        virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer);
    NCAcker* acker_;
    int ts_echo_bugfix_;
    int ts_echo_rfc1323_;     // conforms to rfc1323 for timestamps echo
                // Added by Andrei Gurtov
    friend void NCSacker::configure(TcpNCSink*);
    TracedInt max_sack_blocks_;    /* used only by sack sinks */
    Packet* save_;        /* place to stash saved packet while delaying */
                /* used by DelAckSink */
    int generate_dsacks_;    // used only by sack sinks
    int qs_enabled_; // to enable QuickStart
    int RFC2581_immediate_ack_;    // Used to generate ACKs immediately
    int bytes_;      // for JOBS
                    // for RFC2581-compliant gap-filling.
    double lastreset_;     /* W.N. used for detecting packets  */
                /* from previous incarnations */
        int ecn_syn_;           /* allow SYN/ACK packets to be ECN-capable */
};
class NCDelAckSink;
class NCDelayTimer : public TimerHandler {
public:
    NCDelayTimer(NCDelAckSink *a) : TimerHandler() { a_ = a; }
protected:
    virtual void expire(Event *e);
    NCDelAckSink *a_;
};
class NCDelAckSink : public TcpNCSink {
public:
    NCDelAckSink(NCAcker* acker);
    void recv(Packet* pkt, Handler*);
    virtual void timeout(int tno);
    void reset();
protected:
    double interval_;
    NCDelayTimer delay_timer_;
};
#endif
--------------------分割线-----------------------------------
//tcp-sink-nc.cc
#include "flags.h"
#include "ip.h"
#include "tcp-sink-nc.h"
#include "hdr_qs.h"
static class TcpNCSinkClass : public TclClass {
public:
    TcpNCSinkClass() : TclClass("Agent/TCPNCSink") {}
    TclObject* create(int, const char*const*) {
        return (new TcpNCSink(new NCAcker));
    }
} class_tcpncsink;
NCAcker::NCAcker() : next_(0), maxseen_(0), wndmask_(MWM), ecn_unacked_(0),
    ts_to_echo_(0), last_ack_sent_(0)
{
    seen_ = new int[MWS];
    memset(seen_, 0, (sizeof(int) * (MWS)));
}
void NCAcker::reset()
{
    next_ = 0;
    maxseen_ = 0;
    memset(seen_, 0, (sizeof(int) * (wndmask_ + 1)));
}    
// dynamically increase the seen buffer as needed
// size must be a factor of two for the wndmask_ to work...
void NCAcker::resize_buffers(int sz) {
    int* new_seen = new int[sz];
    int new_wndmask = sz - 1;
    
    if(!new_seen){
        fprintf(stderr, "Unable to allocate buffer seen_[%i]\n", sz);
        exit(1);
    }
    
    memset(new_seen, 0, (sizeof(int) * (sz)));
    
    for(int i = next_; i <= maxseen_+1; i++){
        new_seen[i & new_wndmask] = seen_[i&wndmask_];
    }
    
    delete[] seen_;
    seen_ = new_seen;      
    wndmask_ = new_wndmask;
    return;
}
void NCAcker::update_ts(int seqno, double ts, int rfc1323)
{
    // update timestamp if segment advances with ACK.
        // Code changed by Andrei Gurtov.
        if (rfc1323 && seqno == last_ack_sent_ + 1)
               ts_to_echo_ = ts;
        else if (ts >= ts_to_echo_ && seqno <= last_ack_sent_ + 1)
               //rfc1323-bis, update timestamps from duplicate segments
               ts_to_echo_ = ts;
}
// returns number of bytes that can be "delivered" to application
// also updates the receive window (i.e. next_, maxseen, and seen_ array)
int NCAcker::update(int seq, int numBytes)
{
    bool just_marked_as_seen = FALSE;
    is_dup_ = FALSE;
    // start by assuming the segment hasn't been received before
    if (numBytes <= 0)
        printf("Error, received TCP packet size <= 0\n");
    int numToDeliver = 0;
    while(seq + 1 - next_ >= wndmask_) {
        // next_ is next packet expected; wndmask_ is the maximum
        // window size minus 1; if somehow the seqno of the
        // packet is greater than the one we're expecting+wndmask_,
        // then resize the buffer.
        resize_buffers((wndmask_+1)*2);
    }
    if (seq > maxseen_) {
        // the packet is the highest one we've seen so far
        int i;
        for (i = maxseen_ + 1; i < seq; ++i)
            seen_[i & wndmask_] = 0;
        // we record the packets between the old maximum and
        // the new max as being "unseen" i.e. 0 bytes of each
        // packet have been received
        maxseen_ = seq;
        seen_[maxseen_ & wndmask_] = numBytes;
        // store how many bytes have been seen for this packet
        seen_[(maxseen_ + 1) & wndmask_] = 0;
        // clear the array entry for the packet immediately
        // after this one
        just_marked_as_seen = TRUE;
        // necessary so this packet isn't confused as being a duplicate
    }
    int next = next_;
    if (seq < next) {
        // Duplicate packet case 1: the packet is to the left edge of
        // the receive window; therefore we must have seen it
        // before
#ifdef DEBUGDSACK
        printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
#endif
        is_dup_ = TRUE;
    }
    if (seq >= next && seq <= maxseen_) {
        // next is the left edge of the recv window; maxseen_
        // is the right edge; execute this block if there are
        // missing packets in the recv window AND if current
        // packet falls within those gaps
        if (seen_[seq & wndmask_] && !just_marked_as_seen) {
        // Duplicate case 2: the segment has already been
        // recorded as being received (AND not because we just
        // marked it as such)
            is_dup_ = TRUE;
#ifdef DEBUGDSACK
            printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
#endif
        }
        seen_[seq & wndmask_] = numBytes;
        // record the packet as being seen
        while (seen_[next & wndmask_]) {
            // this loop first gets executed if seq==next;
            // i.e., this is the next packet in order that
            // we've been waiting for.  the loop sets how
            // many bytes we can now deliver to the
            // application, due to this packet arriving
            // (and the prior arrival of any segments
            // immediately to the right)
            numToDeliver += seen_[next & wndmask_];
            ++next;
        }
        next_ = next;
        // store the new left edge of the window
    }
    return numToDeliver;
}
TcpNCSink::TcpNCSink(NCAcker* acker) : Agent(PT_ACK), acker_(acker), save_(NULL),
    lastreset_(0.0)
{
    bytes_ = 0;
    bind("bytes_", &bytes_);
    /*
     * maxSackBlocks_ does wierd tracing things.
     * don't make it delay-bound yet.
     */
#if defined(TCP_DELAY_BIND_ALL) && 0
#else /* ! TCP_DELAY_BIND_ALL */
    bind("maxSackBlocks_", &max_sack_blocks_); // used only by sack
#endif /* TCP_DELAY_BIND_ALL */
}
void
TcpNCSink::delay_bind_init_all()
{
        delay_bind_init_one("packetSize_");
        delay_bind_init_one("ts_echo_bugfix_");
    delay_bind_init_one("ts_echo_rfc1323_");
    delay_bind_init_one("bytes_"); // For throughput measurements in JOBS
        delay_bind_init_one("generateDSacks_"); // used only by sack
    delay_bind_init_one("qs_enabled_");
    delay_bind_init_one("RFC2581_immediate_ack_");
    delay_bind_init_one("ecn_syn_");
#if defined(TCP_DELAY_BIND_ALL) && 0
        delay_bind_init_one("maxSackBlocks_");
#endif /* TCP_DELAY_BIND_ALL */
    Agent::delay_bind_init_all();
}
int
TcpNCSink::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
{
        if (delay_bind(varName, localName, "packetSize_", &size_, tracer)) return TCL_OK;
        if (delay_bind_bool(varName, localName, "ts_echo_bugfix_", &ts_echo_bugfix_, tracer)) return TCL_OK;
    if (delay_bind_bool(varName, localName, "ts_echo_rfc1323_", &ts_echo_rfc1323_, tracer)) return TCL_OK;
        if (delay_bind_bool(varName, localName, "generateDSacks_", &generate_dsacks_, tracer)) return TCL_OK;
        if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_, tracer)) return TCL_OK;
        if (delay_bind_bool(varName, localName, "RFC2581_immediate_ack_", &RFC2581_immediate_ack_, tracer)) return TCL_OK;
    if (delay_bind_bool(varName, localName, "ecn_syn_", &ecn_syn_ ,tracer)) return TCL_OK;
#if defined(TCP_DELAY_BIND_ALL) && 0
        if (delay_bind(varName, localName, "maxSackBlocks_", &max_sack_blocks_, tracer)) return TCL_OK;
#endif /* TCP_DELAY_BIND_ALL */
        return Agent::delay_bind_dispatch(varName, localName, tracer);
}
void NCAcker::append_ack(hdr_cmn*, hdr_tcp*, int) const
{
}
void NCAcker::update_ecn_unacked(int value)
{
    ecn_unacked_ = value;
}
int TcpNCSink::command(int argc, const char*const* argv)
{
    if (argc == 2) {
        if (strcmp(argv[1], "reset") == 0) {
            reset();
            return (TCL_OK);
        }
        if (strcmp(argv[1], "resize_buffers") == 0) {
            // no need for this as seen buffer set dynamically
            fprintf(stderr,"DEPRECIATED: resize_buffers\n");
            return (TCL_OK);
        }
    }
    return (Agent::command(argc, argv));
}
void TcpNCSink::reset()
{
    acker_->reset();    
    save_ = NULL;
    lastreset_ = Scheduler::instance().clock(); /* W.N. - for detecting */
                /* packets from previous incarnations */
}
void TcpNCSink::ack(Packet* opkt)
{
    Packet* npkt = allocpkt();
    // opkt is the "old" packet that was received
    // npkt is the "new" packet being constructed (for the ACK)
    double now = Scheduler::instance().clock();
    hdr_tcp *otcp = hdr_tcp::access(opkt);
    hdr_ip *oiph = hdr_ip::access(opkt);
    hdr_tcp *ntcp = hdr_tcp::access(npkt);
    if (qs_enabled_) {
        // QuickStart code from Srikanth Sundarrajan.
        hdr_qs *oqsh = hdr_qs::access(opkt);
        hdr_qs *nqsh = hdr_qs::access(npkt);
            if (otcp->seqno() == 0 && oqsh->flag() == QS_REQUEST) {
                    nqsh->flag() = QS_RESPONSE;
                    nqsh->ttl() = (oiph->ttl() - oqsh->ttl()) % 256;
                    nqsh->rate() = oqsh->rate();
            }
            else {
                    nqsh->flag() = QS_DISABLE;
            }
    }
    // get the tcp headers
    ntcp->seqno() = acker_->Seqno();
    // get the cumulative sequence number to put in the ACK; this
    // is just the left edge of the receive window - 1
    ntcp->ts() = now;
    // timestamp the packet
    if (ts_echo_bugfix_)  /* TCP/IP Illustrated, Vol. 2, pg. 870 */
        ntcp->ts_echo() = acker_->ts_to_echo();
    else
        ntcp->ts_echo() = otcp->ts();
    // echo the original's time stamp
    hdr_ip* oip = hdr_ip::access(opkt);
    hdr_ip* nip = hdr_ip::access(npkt);
    // get the ip headers
    nip->flowid() = oip->flowid();
    // copy the flow id
    
    hdr_flags* of = hdr_flags::access(opkt);
    hdr_flags* nf = hdr_flags::access(npkt);
    hdr_flags* sf;
    if (save_ != NULL)
        sf = hdr_flags::access(save_);
    else
        sf = 0;
        // Look at delayed packet being acked.
    if ( (sf != 0 && sf->cong_action()) || of->cong_action() )
        // Sender has responsed to congestion.
        acker_->update_ecn_unacked(0);
    if ( (sf != 0 && sf->ect() && sf->ce())  ||
            (of->ect() && of->ce()) )
        // New report of congestion.  
        acker_->update_ecn_unacked(1);
    if ( (sf != 0 && sf->ect()) || of->ect() )
        // Set EcnEcho bit.  
        nf->ecnecho() = acker_->ecn_unacked();
    if (!of->ect() && of->ecnecho() ||
        (sf != 0 && !sf->ect() && sf->ecnecho()) ) {
         // This is the negotiation for ECN-capability.
         // We are not checking for of->cong_action() also.
         // In this respect, this does not conform to the
         // specifications in the internet draft
        nf->ecnecho() = 1;
        if (ecn_syn_)
            nf->ect() = 1;
    }
    acker_->append_ack(hdr_cmn::access(npkt),
               ntcp, otcp->seqno());
    add_to_ack(npkt);
    // the above function is used in TcpAsymSink
        // Andrei Gurtov
        acker_->last_ack_sent_ = ntcp->seqno();
        // printf("ACK %d ts %f\n", ntcp->seqno(), ntcp->ts_echo());
    
    send(npkt, 0);
    // send it
}
void TcpNCSink::add_to_ack(Packet*)
{
    return;
}
void TcpNCSink::recv(Packet* pkt, Handler*)
{
    int numToDeliver;
    int numBytes = hdr_cmn::access(pkt)->size();
    // number of bytes in the packet just received
    hdr_tcp *th = hdr_tcp::access(pkt);
    /* W.N. Check if packet is from previous incarnation */
    if (th->ts() < lastreset_) {
        // Remove packet and do nothing
        Packet::free(pkt);
        return;
    }
    acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
    // update the timestamp to echo
    
          numToDeliver = acker_->update(th->seqno(), numBytes);
    // update the recv window; figure out how many in-order-bytes
    // (if any) can be removed from the window and handed to the
    // application
    if (numToDeliver) {
        bytes_ += numToDeliver;
        recvBytes(numToDeliver);
    }
    // send any packets to the application
          ack(pkt);
    // ACK the packet
    Packet::free(pkt);
    // remove it from the system
}
static class NCDelSinkClass : public TclClass {
public:
    NCDelSinkClass() : TclClass("Agent/TCPNCSink/NCDelAck") {}
    TclObject* create(int, const char*const*) {
        return (new NCDelAckSink(new NCAcker));
    }
} class_ncdelsink;
NCDelAckSink::NCDelAckSink(NCAcker* acker) : TcpNCSink(acker), delay_timer_(this)
{
    bind_time("interval_", &interval_);
    // Deleted the line below, since this is bound in TcpSink.
    // bind("bytes_", &bytes_); // useby JOBS
}
void NCDelAckSink::reset() {
    if (delay_timer_.status() == TIMER_PENDING)
        delay_timer_.cancel();
    TcpNCSink::reset();
}
void NCDelAckSink::recv(Packet* pkt, Handler*)
{
    int numToDeliver;
    int numBytes = hdr_cmn::access(pkt)->size();
    hdr_tcp *th = hdr_tcp::access(pkt);
    /* W.N. Check if packet is from previous incarnation */
    if (th->ts() < lastreset_) {
        // Remove packet and do nothing
        Packet::free(pkt);
        return;
    }
    acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
    numToDeliver = acker_->update(th->seqno(), numBytes);
    if (numToDeliver) {
                bytes_ += numToDeliver; // for JOBS
                recvBytes(numToDeliver);
        }
    
        // If there's no timer and the packet is in sequence, set a timer.
        // Otherwise, send the ack and update the timer.
        if (delay_timer_.status() != TIMER_PENDING &&
                                th->seqno() == acker_->Seqno()) {
                // There's no timer, so we can set one and choose
        // to delay this ack.
        // If we're following RFC2581 (section 4.2) exactly,
        // we should only delay the ACK if we're know we're
        // not doing recovery, i.e. not gap-filling.
        // Since this is a change to previous ns behaviour,
        // it's controlled by an optional bound flag.
        // discussed April 2000 in the ns-users list archives.
        if (RFC2581_immediate_ack_ &&
            (th->seqno() < acker_->Maxseen())) {
            // don't delay the ACK since
            // we're filling in a gap
        } else {
            // delay the ACK and start the timer.
                    save_ = pkt;
                    delay_timer_.resched(interval_);
                    return;
        }
        }
        // If there was a timer, turn it off.
    if (delay_timer_.status() == TIMER_PENDING)
        delay_timer_.cancel();
    ack(pkt);
        if (save_ != NULL) {
                Packet::free(save_);
                save_ = NULL;
        }
    Packet::free(pkt);
}
void NCDelAckSink::timeout(int)
{
    // The timer expired so we ACK the last packet seen.
    if ( save_ != NULL ) {
        Packet* pkt = save_;
        ack(pkt);
        save_ = NULL;
        Packet::free(pkt);
    }
}
void NCDelayTimer::expire(Event* /*e*/) {
    a_->timeout(0);
}
/* "sack1-tcp-sink" is for Matt and Jamshid's implementation of sack. */
class NCSackStack {
protected:
    int size_;
    int cnt_;
    struct Sf_Entry {
        int left_;
        int right_;
    } *SFE_;
public:
    NCSackStack(int);     // create a SackStack of size (int)
    ~NCSackStack();
    int& head_right(int n = 0) { return SFE_[n].right_; }
    int& head_left(int n = 0) { return SFE_[n].left_; }
    int cnt() { return cnt_; }      // how big is the stack
    void reset() {
        register int i;
        for (i = 0; i < cnt_; i++)
            SFE_[i].left_ = SFE_[i].right_ = -1;
        cnt_ = 0;
    }
    inline void push(int n = 0) {
         if (cnt_ >= size_) cnt_ = size_ - 1;  // overflow check
        register int i;
        for (i = cnt_-1; i >= n; i--)
            SFE_[i+1] = SFE_[i];    // not efficient for big size
        cnt_++;
    }
    inline void pop(int n = 0) {
        register int i;
        for (i = n; i < cnt_-1; i++)
            SFE_[i] = SFE_[i+1];    // not efficient for big size
        SFE_[i].left_ = SFE_[i].right_ = -1;
        cnt_--;
    }
};
NCSackStack::NCSackStack(int sz)
{
    register int i;
    size_ = sz;
    SFE_ = new Sf_Entry[sz];
    for (i = 0; i < sz; i++)
        SFE_[i].left_ = SFE_[i].right_ = -1;
    cnt_ = 0;
}
NCSackStack::~NCSackStack()
{
    delete SFE_;
}
static class NCSack1TcpSinkClass : public TclClass {
public:
        NCSack1TcpSinkClass() : TclClass("Agent/TCPNCSink/NCSack1") {}
    TclObject* create(int, const char*const*) {
        NCSacker* sacker = new NCSacker;
        TcpNCSink* sink = new TcpNCSink(sacker);
        sacker->configure(sink);
        return (sink);
        }
} class_ncsack1tcpsink;
static class NCSack1DelAckTcpSinkClass : public TclClass {
public:
    NCSack1DelAckTcpSinkClass() : TclClass("Agent/TCPNCSink/NCSack1/NCDelAck") {}
    TclObject* create(int, const char*const*) {
        NCSacker* sacker = new NCSacker;
        TcpNCSink* sink = new NCDelAckSink(sacker);
        sacker->configure(sink);
        return (sink);
    }
} class_ncsack1delacktcpsink;
void NCSacker::configure(TcpNCSink *sink)
{
    if (sink == NULL) {
        fprintf(stderr, "warning: NCSacker::configure(): no TCP NC sink!\n");
        return;
    }
    TracedInt& nblocks = sink->max_sack_blocks_;
    if (int(nblocks) > NSA) {
        fprintf(stderr, "warning(NCSacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks));
        nblocks = NSA;
    }
    sf_ = new NCSackStack(int(nblocks));
    nblocks.tracer(this);
    base_nblocks_ = int(nblocks);
    dsacks_ = &(sink->generate_dsacks_);
}
void
NCSacker::trace(TracedVar *v)
{
    // we come here if "nblocks" changed
    TracedInt* ti = (TracedInt*) v;
    if (int(*ti) > NSA) {
        fprintf(stderr, "warning(NCSacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti));
        *ti = NSA;
    }
    int newval = int(*ti);
    delete sf_;
    sf_ = new NCSackStack(newval);
    base_nblocks_ = newval;
}
void NCSacker::reset()
{
    sf_->reset();
    NCAcker::reset();
}
NCSacker::~NCSacker()
{
    delete sf_;
}
void NCSacker::append_ack(hdr_cmn* ch, hdr_tcp* h, int old_seqno) const
{
    // ch and h are the common and tcp headers of the Ack being constructed
    // old_seqno is the sequence # of the packet we just got
    
        int sack_index, i, sack_right, sack_left;
    int recent_sack_left, recent_sack_right;
          
    int seqno = Seqno();
    // the last in-order packet seen (i.e. the cumulative ACK # - 1)
        sack_index = 0;
    sack_left = sack_right = -1;
    // initialization; sack_index=0 and sack_{left,right}= -1
        if (old_seqno < 0) {
                printf("Error: invalid packet number %d\n", old_seqno);
        } else if (seqno >= maxseen_ && (sf_->cnt() != 0))
        sf_->reset();
    // if the Cumulative ACK seqno is at or beyond the right edge
    // of the window, and if the SackStack is not empty, reset it
    // (empty it)
    else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) {
        // Otherwise, if the received packet is to the left of
        // the right edge of the receive window (but not at
        // the right edge), OR if it is a duplicate, AND we
        // can have 1 or more Sack blocks, then execute the
        // following, which computes the most recent Sack
        // block
        if ((*dsacks_) && is_dup_) {
            // Record the DSACK Block
            h->sa_left(sack_index) = old_seqno;
            h->sa_right(sack_index) = old_seqno+1;
            // record the block
            sack_index++;
#ifdef DEBUGDSACK
            printf("%f\t Generating D-SACK for packet %d\n", Scheduler::instance().clock(),old_seqno);
#endif
            
        }
        //  Build FIRST (traditional) SACK block
        // If we already had a DSACK block due to a duplicate
        // packet, and if that duplicate packet is in the
        // receiver's window (i.e. the packet's sequence
        // number is > than the cumulative ACK) then the
        // following should find the SACK block it's a subset
        // of.  If it's <= cum ACK field then the following
        // shouldn't record a superset SACK block for it.
                if (sack_index >= base_nblocks_) {
            printf("Error: can't use DSACK with less than 2 SACK blocks\n");
        } else {
                sack_right=-1;
        // look rightward for first hole
        // start at the current packet
                for (i=old_seqno; i<=maxseen_; i++) {
            if (!seen_[i & wndmask_]) {
                sack_right=i;
                break;
            }
        }
        // if there's no hole set the right edge of the sack
        // to be the next expected packet
                if (sack_right == -1) {
            sack_right = maxseen_+1;
                }
        // if the current packet's seqno is smaller than the
        // left edge of the window, set the sack_left to 0
        if (old_seqno <= seqno) {
            sack_left = 0;
            // don't record/send the block
        } else {
            // look leftward from right edge for first hole
                    for (i = sack_right-1; i > seqno; i--) {
                if (!seen_[i & wndmask_]) {
                    sack_left = i+1;
                    break;
                }
                    }
            h->sa_left(sack_index) = sack_left;
            h->sa_right(sack_index) = sack_right;
            
            // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
            // record the block
            sack_index++;
        }
        recent_sack_left = sack_left;
        recent_sack_right = sack_right;
        // first sack block is built, check the others
        // make sure that if max_sack_blocks has been made
        // large from tcl we don't over-run the stuff we
        // allocated in Sacker::Sacker()
        int k = 0;
                while (sack_index < base_nblocks_) {
            sack_left = sf_->head_left(k);
            sack_right = sf_->head_right(k);
            // no more history
            if (sack_left < 0 || sack_right < 0 ||
                sack_right > maxseen_ + 1)
                break;
            // newest ack "covers up" this one
            if (recent_sack_left <= sack_left &&
                recent_sack_right >= sack_right) {
                sf_->pop(k);
                continue;
            }
            h->sa_left(sack_index) = sack_left;
            h->sa_right(sack_index) = sack_right;
            
            // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
            
            // store the old sack (i.e. move it down one)
            sack_index++;
            k++;
                }
        if (old_seqno > seqno) {
             /* put most recent block onto stack */
            sf_->push();
            // this just moves things down 1 from the
            // beginning, but it doesn't push any values
            // on the stack
            sf_->head_left() = recent_sack_left;
            sf_->head_right() = recent_sack_right;
            // this part stores the left/right values at
            // the top of the stack (slot 0)
        }
        } // this '}' is for the DSACK base_nblocks_ >= test;
          // (didn't feel like re-indenting all the code and
          // causing a large diff)
        
        }
    h->sa_length() = sack_index;
    // set the Length of the sack stack in the header
    ch->size() += sack_index * 8;
    // change the size of the common header to account for the
    // Sack strings (2 4-byte words for each element)
}
----------------------------分割线-----------------------------------
//tcp-asym-sink-nc.cc
#ifndef lint
static const char rcsid[] =
    "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp-asym-sink.cc,v 1.17 2003/08/14 04:26:42 sfloyd Exp $ (UCB)";
#endif
#include "template.h"
#include "flags.h"
#include "tcp-sink-nc.h"
#include "tcp-asym.h"
class TcpNCAsymSink : public NCDelAckSink {
public:
    TcpNCAsymSink(NCAcker*);
    virtual void recv(Packet* pkt, Handler* h);
    virtual void timeout(int tno);
protected:
    virtual void add_to_ack(Packet* pkt);
    int delackcount_;    /* the number of consecutive packets that have
                   not been acked yet */
    int maxdelack_;        /* the maximum extent to which acks can be
                   delayed */
    int delackfactor_;    /* the dynamically varying limit on the extent
                   to which acks can be delayed */
    int delacklim_;        /* limit on the extent of del ack based on the
                   sender's window */
    double ts_ecn_;        /* the time when an ECN was received last */
    double ts_decrease_;    /* the time when delackfactor_ was decreased last */
    double highest_ts_echo_;/* the highest timestamp echoed by the peer */
};    
static class TcpNCAsymSinkClass : public TclClass {
public:
    TcpNCAsymSinkClass() : TclClass("Agent/TCPNCSink/Asym") {}
    TclObject* create(int, const char*const*) {
        return (new TcpNCAsymSink(new NCAcker));
    }
} class_tcp_nc_asymsink;
TcpNCAsymSink::TcpNCAsymSink(NCAcker* acker) : NCDelAckSink(acker), delackcount_(0),
    delackfactor_(1), delacklim_(0), ts_ecn_(0), ts_decrease_(0)
{
    bind("maxdelack_", &maxdelack_);
}
/* Add fields to the ack. Not needed? */
void TcpNCAsymSink::add_to_ack(Packet* pkt)
{
    hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
    tha->ackcount() = delackcount_;
}
void TcpNCAsymSink::recv(Packet* pkt, Handler*)
{
    int olddelackfactor = delackfactor_;
    int olddelacklim = delacklim_;
    int max_sender_can_send = 0;
    hdr_flags *fh = hdr_flags::access(pkt);
    hdr_tcp *th = hdr_tcp::access(pkt);
    hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
    double now = Scheduler::instance().clock();
    int numBytes = hdr_cmn::access(pkt)->size();
    acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
    acker_->update(th->seqno(), numBytes);
#if 0  // johnh
    int numToDeliver;
    /* XXX if the #if 0 is removed, delete the call to acker_->update() above */
    numToDeliver = acker_->update(th->seqno(), numBytes);
    if (numToDeliver)
        recvBytes(numToDeliver);
#endif /* 0 */
    /* determine the highest timestamp the sender has echoed */
    highest_ts_echo_ = max(highest_ts_echo_, th->ts_echo());
    /*
     * if we receive an ECN and haven't received one in the past
     * round-trip, double delackfactor_ (and consequently halve
     * the frequency of acks) subject to a maximum
     */
    if (fh->ecnecho() && highest_ts_echo_ >= ts_ecn_) {
        delackfactor_ = min(2*delackfactor_, maxdelack_);
        ts_ecn_ = now;
    }
    /*
     * else if we haven't received an ECN in the past round trip and
     * haven't (linearly) decreased delackfactor_ in the past round
     * trip, we decrease delackfactor_ by 1 (and consequently increase
     * the frequency of acks) subject to a minimum
     */
    else if (highest_ts_echo_ >= ts_ecn_ && highest_ts_echo_ >= ts_decrease_) {
        delackfactor_ = max(delackfactor_ - 1, 1);
        ts_decrease_ = now;
    }
    /*
         * if this is the next packet in sequence, we can consider delaying the ack.
     * Set delacklim_ based on how much data the sender can send if we don't
     * send back any more acks. The idea is to avoid stalling the sender because
     * of a lack of acks.
         */
        if (th->seqno() == acker_->Seqno()) {
        max_sender_can_send = (int) min(tha->win()+acker_->Seqno()-tha->highest_ack(), tha->max_left_to_send());
        /* XXXX we use a safety factor 2 */
        delacklim_ = min(maxdelack_, max_sender_can_send/2);
    }
    else
        delacklim_ = 0;
    if (delackfactor_ < delacklim_)
        delacklim_ = delackfactor_;
    /*
     * Log values of variables of interest. Since this is the only place
     * where this is done, we decided against using a more general method
     * as used for logging TCP sender state variables.
     */
    if (channel_ && (olddelackfactor != delackfactor_ || olddelacklim != delacklim_)) {
        char wrk[500];
        int n;
        /* we print src and dst in reverse order to conform to sender side */
        sprintf(wrk, "time: %-6.3f saddr: %-2d sport: %-2d daddr:"
            " %-2d dport: %-2d dafactor: %2d dalim: %2d max_scs:"
            " %4d win: %4d\n", now, addr(), port(),
            daddr(), dport(), delackfactor_,
            delacklim_,max_sender_can_send, tha->win());  
        n = strlen(wrk);
        wrk[n] = '\n';
        wrk[n+1] = 0;
        (void)Tcl_Write(channel_, wrk, n+1);
        wrk[n] = 0;
    }
        
    delackcount_++;
    /* check if we have waited long enough that we should send an ack */
    if (delackcount_ < delacklim_) { /* it is not yet time to send an ack */
        /* if the delayed ack timer is not set, set it now */
        if (!(delay_timer_.status() == TIMER_PENDING)) {
            save_ = pkt;
            delay_timer_.resched(interval_);
        }
        else {
            hdr_tcp *sth = hdr_tcp::access(save_);
            /* save the pkt with the more recent timestamp */
            if (th->ts() > sth->ts()) {
                Packet::free(save_);
                save_ = pkt;
            }
        }
        return;
    }
    else { /* send back an ack now */
        if (delay_timer_.status() == TIMER_PENDING) {
            delay_timer_.cancel();
            Packet::free(save_);
            save_ = 0;
        }
        hdr_flags* hf = hdr_flags::access(pkt);
        hf->ect() = 1;
        ack(pkt);
        delackcount_ = 0;
        Packet::free(pkt);
    }
}
void TcpNCAsymSink::timeout(int /*tno*/)
{
    /*
     * The timer expired so we ACK the last packet seen.
     */
    Packet* pkt = save_;
    delackcount_ = 0;
    ack(pkt);
    save_ = 0;
    Packet::free(pkt);
}
-------------------------------分割线----------------------------------
上面三个文件是我新建的。基本上就是把原有的TCPSink相关文件复制了一遍,改了类的名字,除此以外在tcl/lib文件夹里面ns-default.tcl添加了
Agent/TCPNCSink set accessible_var_ true
Agent/TCPNCSink set sport_        0
Agent/TCPNCSink set dport_        0        
#XXX other kinds of sinks -> should reparent
Agent/TCPNCSink set packetSize_ 40
Agent/TCPNCSink set maxSackBlocks_ 3
Agent/TCPNCSink set ts_echo_bugfix_ true ;    # default changed, 2003/8/13
Agent/TCPNCSink set ts_echo_rfc1323_ false ;    # default added, 2003/8/13
Agent/TCPNCSink set generateDSacks_ false
Agent/TCPNCSink set qs_enabled_ false
Agent/TCPNCSink set RFC2581_immediate_ack_ true
Agent/TCPNCSink set bytes_ 0
Agent/TCPNCSink set ecn_syn_ false ;    # Added 2005/11/21 for SYN/ACK pkts.
Agent/TCPNCSink/NCDelAck set interval_ 100ms
catch {
    Agent/TCPNCSink/Asym set interval_ 100ms
    Agent/TCPNCSink/Asym set maxdelack_ 5
}
Agent/TCPNCSink/NCSack1/NCDelAck set interval_ 100ms
---------------------------------------
在ns-agent.tcl里添加了:
Agent/TCPNCSink instproc init {} {
    eval $self next
    set ns [Simulator instance]
    $ns create-eventtrace Event $self
}
-----------------------------------
还修改了makefile。
但是编译通过,却没有生成新的类。
这是怎么回事?

到底是出错了呢,还是完成后没有生成你要的obj?
如果是后者,你看看console里的make输出,有没有CC tcp-sink-nc.cxx之类的字样。

Just run " make install ", after you run "make".
Also, maybe you should declare the default value of all the Otcl
variables of your *.cc file in /ns/tcl/lib/ns-default.tcl, this
will keep away from some ugly warnings.
看不出问题,可能你的ns并没有调用新编译的那个,因为make之后的文件是
放在当前目录。。。
我猜平常你应该直接 ns 。。。这样的,那就是这个问题。
因为如果你没有成功编译agent的话,那些在ns-default.tcl中的命令
会无法运行,并且错误会在你的脚本执行以前就出现。但是你这里没有
估计是你把可执行文件搞错了

问题解决了:
make clean
make depend
make
make install
都执行一遍才行

...
果然你调用了老版的ns
install就是要把ns的执行文件放到系统的某个目录中,这个目录在path环境变量
里。所以你要make install

Top