📄 tcp-sink.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) 1991-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lintstatic const char rcsid[] = "@(#) $Header: /usr/src/mash/repository/vint/ns-2/tcp-sink.cc,v 1.41 2000/04/15 03:09:06 sfloyd Exp $ (LBL)";#endif#include "flags.h"#include "ip.h"#include "tcp-sink.h"#define SINKSEQ//SHKFILE *seqfile;FILE *tcpseq2;static class TcpSinkClass : public TclClass {public: TcpSinkClass() : TclClass("Agent/TCPSink") {} TclObject* create(int, const char*const*) { return (new TcpSink(new Acker)); }} class_tcpsink;Acker::Acker() : next_(0), maxseen_(0), ecn_unacked_(0), ts_to_echo_(0){ memset(seen_, 0, sizeof(seen_));}void Acker::reset() { next_ = 0; maxseen_ = 0; memset(seen_, 0, sizeof(seen_));} void Acker::update_ts(int seqno, double ts){ if (ts >= ts_to_echo_ && seqno <= next_) 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 Acker::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; if (seq - next_ >= MWM) { // next_ is next packet expected; MWM is the maximum // window size minus 1; if somehow the seqno of the // packet is greater than the one we're expecting+MWM, // then ignore it. return 0; } 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 & MWM] = 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_ & MWM] = numBytes; // store how many bytes have been seen for this packet seen_[(maxseen_ + 1) & MWM] = 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 & MWM] && !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 & MWM] = numBytes; // record the packet as being seen while (seen_[next & MWM]) { // 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 & MWM]; ++next; } next_ = next; // store the new left edge of the window } return numToDeliver;}TcpSink::TcpSink(Acker* acker) : Agent(PT_ACK), acker_(acker), save_(NULL), recvBytes_(0) /* Wan */{#ifdef SINKSEQ//SHK seqfile = fopen("seqfile", "w"); tcpseq2 = fopen("tcpseq2", "w");#endif /* * 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 */ /* Wan: add a tcl bound variable */ bind("recvBytes", &recvBytes_);}voidTcpSink::delay_bind_init_all(){ delay_bind_init_one("packetSize_"); delay_bind_init_one("ts_echo_bugfix_"); delay_bind_init_one("generateDSacks_"); // used only by sack delay_bind_init_one("RFC2581_immediate_ack_");#if defined(TCP_DELAY_BIND_ALL) && 0 delay_bind_init_one("maxSackBlocks_");#endif /* TCP_DELAY_BIND_ALL */ Agent::delay_bind_init_all();}intTcpSink::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, "generateDSacks_", &generate_dsacks_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "RFC2581_immediate_ack_", &RFC2581_immediate_ack_, 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 Acker::append_ack(hdr_cmn*, hdr_tcp*, int) const{}void Acker::update_ecn_unacked(int value){ ecn_unacked_ = value;}int TcpSink::command(int argc, const char*const* argv){ if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { reset(); return (TCL_OK); } } return (Agent::command(argc, argv));}void TcpSink::reset() { acker_->reset(); save_ = NULL;#ifdef SINKSEQ fclose(seqfile);#endif}void TcpSink::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_flags *sf; hdr_tcp *otcp = hdr_tcp::access(opkt); hdr_tcp *ntcp = hdr_tcp::access(npkt); // get the tcp headers ntcp->seqno() = acker_->Seqno();#ifdef SINKSEQ //fprintf(seqfile, "tcpseq:%d ack:%d\n",otcp->seqno(), ntcp->seqno()); fprintf(tcpseq2, "%f %d\n",Scheduler::instance().clock(), ntcp->seqno());#endif // 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*)opkt->access(off_ip_); hdr_ip* nip = (hdr_ip*)npkt->access(off_ip_); // get the ip headers nip->flowid() = oip->flowid(); // copy the flow id hdr_flags* of = (hdr_flags*)opkt->access(off_flags_); hdr_flags* nf = (hdr_flags*)npkt->access(off_flags_); if (save_ != NULL) sf = (hdr_flags*)save_->access(off_flags_); // Look at delayed packet being acked. if ( (save_ != NULL && sf->cong_action()) || of->cong_action() ) // Sender has responsed to congestion. acker_->update_ecn_unacked(0); if ( (save_ != NULL && sf->ect() && sf->ce()) || (of->ect() && of->ce()) ) // New report of congestion. acker_->update_ecn_unacked(1); if ( (save_ != NULL && sf->ect()) || of->ect() ) // Set EcnEcho bit. nf->ecnecho() = acker_->ecn_unacked(); if (!of->ect() && of->ecnecho() || (save_ != NULL && !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; acker_->append_ack((hdr_cmn*)npkt->access(off_cmn_), ntcp, otcp->seqno()); add_to_ack(npkt); // the above function is used in TcpAsymSink send(npkt, 0); // send it}void TcpSink::add_to_ack(Packet*){ return;}void TcpSink::recv(Packet* pkt, Handler*){ int numToDeliver; int numBytes = ((hdr_cmn*)pkt->access(off_cmn_))->size(); // number of bytes in the packet just received hdr_tcp *th = hdr_tcp::access(pkt); acker_->update_ts(th->seqno(),th->ts()); // 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) recvBytes(numToDeliver); // send any packets to the application ack(pkt); // ACK the packet Packet::free(pkt); // remove it from the system}/* Added by Wan: */void TcpSink::recvBytes(int bytes){ double now = Scheduler::instance().clock(); recvBytes_ += bytes;}static class DelSinkClass : public TclClass {public: DelSinkClass() : TclClass("Agent/TCPSink/DelAck") {} TclObject* create(int, const char*const*) { return (new DelAckSink(new Acker)); }} class_delsink;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -