📄 tcp-full.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) Intel Corporation 2001. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Copyright (c) 1997, 1998 The 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 Network Research * Group at Lawrence Berkeley National 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. *//* * Full-TCP : A two-way TCP very similar to the 4.4BSD version of Reno TCP. * This version also includes variants Tahoe, NewReno, and SACK. * * This code below has received a fairly major restructuring (Aug. 2001). * The ReassemblyQueue structure is now removed to a separate module and * entirely re-written. * Also, the SACK functionality has been re-written (almost) entirely. * -KF [kfall@intel.com] * * This code below was motivated in part by code contributed by * Kathie Nichols (nichols@baynetworks.com). The code below is based primarily * on the 4.4BSD TCP implementation. -KF [kfall@ee.lbl.gov] * * Kathie Nichols and Van Jacobson have contributed significant bug fixes, * especially with respect to the the handling of sequence numbers during * connection establishment/clearin. Additional fixes have followed * theirs. * * Fixes for gensack() and ReassemblyQueue::add() contributed by Richard * Mortier <Richard.Mortier@cl.cam.ac.uk> * * Some warnings and comments: * this version of TCP will not work correctly if the sequence number * goes above 2147483648 due to sequence number wrap * * this version of TCP by default sends data at the beginning of a * connection in the "typical" way... That is, * A ------> SYN ------> B * A <----- SYN+ACK ---- B * A ------> ACK ------> B * A ------> data -----> B * * there is no dynamic receiver's advertised window. The advertised * window is simulated by simply telling the sender a bound on the window * size (wnd_). * * in real TCP, a user process performing a read (via PRU_RCVD) * calls tcp_output each time to (possibly) send a window * update. Here we don't have a user process, so we simulate * a user process always ready to consume all the receive buffer * * Notes: * wnd_, wnd_init_, cwnd_, ssthresh_ are in segment units * sequence and ack numbers are in byte units * * Futures: * there are different existing TCPs with respect to how * ack's are handled on connection startup. Some delay * the ack for the first segment, which can cause connections * to take longer to start up than if we be sure to ack it quickly. * * some TCPs arrange for immediate ACK generation if the incoming segment * contains the PUSH bit * * */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-full.cc,v 1.118 2005/08/02 04:02:58 tomh Exp $ (LBL)";#endif#include "ip.h"#include "tcp-full.h"#include "flags.h"#include "random.h"#include "template.h"#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif/* * Tcl Linkage for the following: * Agent/TCP/FullTcp, Agent/TCP/FullTcp/Tahoe, * Agent/TCP/FullTcp/Newreno, Agent/TCP/FullTcp/Sack * * See tcl/lib/ns-default.tcl for init methods for * Tahoe, Newreno, and Sack */static class FullTcpClass : public TclClass { public: FullTcpClass() : TclClass("Agent/TCP/FullTcp") {} TclObject* create(int, const char*const*) { return (new FullTcpAgent()); }} class_full;static class TahoeFullTcpClass : public TclClass { public: TahoeFullTcpClass() : TclClass("Agent/TCP/FullTcp/Tahoe") {} TclObject* create(int, const char*const*) { // ns-default sets reno_fastrecov_ to false return (new TahoeFullTcpAgent()); }} class_tahoe_full;static class NewRenoFullTcpClass : public TclClass { public: NewRenoFullTcpClass() : TclClass("Agent/TCP/FullTcp/Newreno") {} TclObject* create(int, const char*const*) { // ns-default sets open_cwnd_on_pack_ to false return (new NewRenoFullTcpAgent()); }} class_newreno_full;static class SackFullTcpClass : public TclClass { public: SackFullTcpClass() : TclClass("Agent/TCP/FullTcp/Sack") {} TclObject* create(int, const char*const*) { // ns-default sets reno_fastrecov_ to false // ns-default sets open_cwnd_on_pack_ to false return (new SackFullTcpAgent()); }} class_sack_full;/* * Delayed-binding variable linkage */voidFullTcpAgent::delay_bind_init_all(){ delay_bind_init_one("segsperack_"); delay_bind_init_one("segsize_"); delay_bind_init_one("tcprexmtthresh_"); delay_bind_init_one("iss_"); delay_bind_init_one("nodelay_"); delay_bind_init_one("data_on_syn_"); delay_bind_init_one("dupseg_fix_"); delay_bind_init_one("dupack_reset_"); delay_bind_init_one("close_on_empty_"); delay_bind_init_one("signal_on_empty_"); delay_bind_init_one("interval_"); delay_bind_init_one("ts_option_size_"); delay_bind_init_one("reno_fastrecov_"); delay_bind_init_one("pipectrl_"); delay_bind_init_one("open_cwnd_on_pack_"); delay_bind_init_one("halfclose_"); delay_bind_init_one("nopredict_"); delay_bind_init_one("spa_thresh_"); TcpAgent::delay_bind_init_all(); reset();}intFullTcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer){ if (delay_bind(varName, localName, "segsperack_", &segs_per_ack_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "segsize_", &maxseg_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "tcprexmtthresh_", &tcprexmtthresh_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "iss_", &iss_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "spa_thresh_", &spa_thresh_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "nodelay_", &nodelay_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "data_on_syn_", &data_on_syn_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "dupseg_fix_", &dupseg_fix_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "dupack_reset_", &dupack_reset_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "close_on_empty_", &close_on_empty_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "signal_on_empty_", &signal_on_empty_, tracer)) return TCL_OK; if (delay_bind_time(varName, localName, "interval_", &delack_interval_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "ts_option_size_", &ts_option_size_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "reno_fastrecov_", &reno_fastrecov_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "pipectrl_", &pipectrl_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "open_cwnd_on_pack_", &open_cwnd_on_pack_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "halfclose_", &halfclose_, tracer)) return TCL_OK; if (delay_bind_bool(varName, localName, "nopredict_", &nopredict_, tracer)) return TCL_OK; return TcpAgent::delay_bind_dispatch(varName, localName, tracer);}voidSackFullTcpAgent::delay_bind_init_all(){ delay_bind_init_one("clear_on_timeout_"); delay_bind_init_one("sack_rtx_cthresh_"); delay_bind_init_one("sack_rtx_bthresh_"); delay_bind_init_one("sack_block_size_"); delay_bind_init_one("sack_option_size_"); delay_bind_init_one("max_sack_blocks_"); delay_bind_init_one("sack_rtx_threshmode_"); FullTcpAgent::delay_bind_init_all();}intSackFullTcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer){ if (delay_bind_bool(varName, localName, "clear_on_timeout_", &clear_on_timeout_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "sack_rtx_cthresh_", &sack_rtx_cthresh_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "sack_rtx_bthresh_", &sack_rtx_bthresh_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "sack_rtx_threshmode_", &sack_rtx_threshmode_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "sack_block_size_", &sack_block_size_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "sack_option_size_", &sack_option_size_, tracer)) return TCL_OK; if (delay_bind(varName, localName, "max_sack_blocks_", &max_sack_blocks_, tracer)) return TCL_OK; return FullTcpAgent::delay_bind_dispatch(varName, localName, tracer);}intFullTcpAgent::command(int argc, const char*const* argv){ // would like to have some "connect" primitive // here, but the problem is that we get called before // the simulation is running and we want to send a SYN. // Because no routing exists yet, this fails. // Instead, see code in advance(). // // listen can happen any time because it just changes state_ // // close is designed to happen at some point after the // simulation is running (using an ns 'at' command) if (argc == 2) { if (strcmp(argv[1], "listen") == 0) { // just a state transition listen(); return (TCL_OK); } if (strcmp(argv[1], "close") == 0) { usrclosed(); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "advance") == 0) { advanceby(atoi(argv[2])); return (TCL_OK); } if (strcmp(argv[1], "advanceby") == 0) { advanceby(atoi(argv[2])); return (TCL_OK); } if (strcmp(argv[1], "advance-bytes") == 0) { advance_bytes(atoi(argv[2])); return (TCL_OK); } } if (argc == 4) { if (strcmp(argv[1], "sendmsg") == 0) { sendmsg(atoi(argv[2]), argv[3]); return (TCL_OK); } } return (TcpAgent::command(argc, argv));}/* * "User Interface" Functions for Full TCP * advanceby(number of packets) * advance_bytes(number of bytes) * sendmsg(int bytes, char* buf) * listen * close *//* * the 'advance' interface to the regular tcp is in packet * units. Here we scale this to bytes for full tcp. * * 'advance' is normally called by an "application" (i.e. data source) * to signal that there is something to send * * 'curseq_' is the sequence number of the last byte provided * by the application. In the case where no data has been supplied * by the application, curseq_ is the iss_. */voidFullTcpAgent::advanceby(int np){ // XXX hack: // because np is in packets and a data source // may pass a *huge* number as a way to tell us // to go forever, just look for the huge number // and if it's there, pre-divide it if (np >= 0x10000000) np /= maxseg_; advance_bytes(np * maxseg_); return;}/* * the byte-oriented interface: advance_bytes(int nbytes) */voidFullTcpAgent::advance_bytes(int nb){ // // state-specific operations: // if CLOSED or LISTEN, reset and try a new active open/connect // if ESTABLISHED, queue and try to send more // if SYN_SENT or SYN_RCVD, just queue // if above ESTABLISHED, we are closing, so don't allow // switch (state_) { case TCPS_CLOSED: case TCPS_LISTEN: reset(); curseq_ = iss_ + nb; connect(); // initiate new connection break; case TCPS_ESTABLISHED: case TCPS_SYN_SENT: case TCPS_SYN_RECEIVED: if (curseq_ < iss_) curseq_ = iss_; curseq_ += nb; break; default: fprintf(stderr, "%f: FullTcpAgent::advance(%s): cannot advance while in state %s\n", now(), name(), statestr(state_)); } if (state_ == TCPS_ESTABLISHED) send_much(0, REASON_NORMAL, maxburst_); return;}/* * If MSG_EOF is set, by setting close_on_empty_ to TRUE, we ensure that * a FIN will be sent when the send buffer emptys. * If DAT_EOF is set, the callback function done_data is called * when the send buffer empty * * When (in the future?) FullTcpAgent implements T/TCP, avoidance of 3-way * handshake can be handled in this function. */voidFullTcpAgent::sendmsg(int nbytes, const char *flags){ if (flags && strcmp(flags, "MSG_EOF") == 0) close_on_empty_ = TRUE; if (flags && strcmp(flags, "DAT_EOF") == 0) signal_on_empty_ = TRUE; if (nbytes == -1) { infinite_send_ = TRUE; advance_bytes(0); } else advance_bytes(nbytes);}/* * do an active open * (in real TCP, see tcp_usrreq, case PRU_CONNECT) */voidFullTcpAgent::connect(){ newstate(TCPS_SYN_SENT); // sending a SYN now sent(iss_, foutput(iss_, REASON_NORMAL)); return;}/* * be a passive opener * (in real TCP, see tcp_usrreq, case PRU_LISTEN) * (for simulation, make this peer's ptype ACKs) */voidFullTcpAgent::listen(){ newstate(TCPS_LISTEN); type_ = PT_ACK; // instead of PT_TCP}/** This function is invoked when the sender buffer is empty. It in turn* invokes the Tcl done_data procedure that was registered with TCP.*/ voidFullTcpAgent::bufferempty(){ signal_on_empty_=FALSE; Tcl::instance().evalf("%s done_data", this->name());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -