📄 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 lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp-sink.cc,v 1.42 2000/09/01 03:04:07 haoboy Exp $ (LBL)";
#endif
#include "flags.h"
#include "ip.h"
#include "tcp-sink.h"
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)
{
/*
* maxSackBlocks_ does wierd tracing things.
* don't make it delay-bound yet.
*/
bind("nodeid_", &nodeid_);
#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
TcpSink::delay_bind_init_all()
{
bind("nodeid_", &nodeid_);
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();
}
int
TcpSink::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;
}
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();
// 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);
if (save_ != NULL)
sf = hdr_flags::access(save_);
// 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::access(npkt),
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::access(pkt)->size();
// number of bytes in the packet just received
hdr_tcp *th = hdr_tcp::access(pkt);
//add here to ignore the elfn notifications
if (th->reason() == TCP_REASON_ELFN)
{
Packet::free(pkt);
FILE *fp = fopen("elfn","a+");
fprintf(fp,"\nSink-- received ELFN notification at SINK %f\n",Scheduler::instance().clock());
fclose(fp);
return;
};
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
// trace the receive event for each tcp connection --Zhenghua
FILE * fp;
char fname[20];
sprintf(fname,"recv%d",nodeid_);
fp = fopen(fname,"a+");
fprintf(fp,"%f\t%d\t%f\n", Scheduler::instance().clock(), th->seqno(),th->ts());
fclose(fp);
Packet::free(pkt);
// remove it from the system
}
static class DelSinkClass : public TclClass {
public:
DelSinkClass() : TclClass("Agent/TCPSink/DelAck") {}
TclObject* create(int, const char*const*) {
return (new DelAckSink(new Acker));
}
} class_delsink;
DelAckSink::DelAckSink(Acker* acker) : TcpSink(acker), delay_timer_(this)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -