📄 tcp-full.cc
字号:
}/* * called when user/application performs 'close' */voidFullTcpAgent::usrclosed(){ curseq_ = maxseq_ - 1; // now, no more data infinite_send_ = FALSE; // stop infinite send switch (state_) { case TCPS_CLOSED: case TCPS_LISTEN: cancel_timers(); newstate(TCPS_CLOSED); finish(); break; case TCPS_SYN_SENT: newstate(TCPS_CLOSED); /* fall through */ case TCPS_LAST_ACK: flags_ |= TF_NEEDFIN; send_much(1, REASON_NORMAL, maxburst_); break; case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: newstate(TCPS_FIN_WAIT_1); flags_ |= TF_NEEDFIN; send_much(1, REASON_NORMAL, maxburst_); break; case TCPS_CLOSE_WAIT: newstate(TCPS_LAST_ACK); flags_ |= TF_NEEDFIN; send_much(1, REASON_NORMAL, maxburst_); break; case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSING: /* usr asked for a close more than once [?] */ fprintf(stderr, "%f FullTcpAgent(%s): app close in bad state %s\n", now(), name(), statestr(state_)); break; default: fprintf(stderr, "%f FullTcpAgent(%s): app close in unknown state %s\n", now(), name(), statestr(state_)); } return;}/* * Utility type functions */voidFullTcpAgent::cancel_timers(){ // cancel: rtx, burstsend, delsnd TcpAgent::cancel_timers(); // cancel: delack delack_timer_.force_cancel();}voidFullTcpAgent::newstate(int state){//printf("%f(%s): state changed from %s to %s\n",//now(), name(), statestr(state_), statestr(state)); state_ = state;}voidFullTcpAgent::prpkt(Packet *pkt){ hdr_tcp *tcph = hdr_tcp::access(pkt); // TCP header hdr_cmn *th = hdr_cmn::access(pkt); // common header (size, etc) //hdr_flags *fh = hdr_flags::access(pkt); // flags (CWR, CE, bits) hdr_ip* iph = hdr_ip::access(pkt); int datalen = th->size() - tcph->hlen(); // # payload bytes fprintf(stdout, " [%d:%d.%d>%d.%d] (hlen:%d, dlen:%d, seq:%d, ack:%d, flags:0x%x (%s), salen:%d, reason:0x%x)\n", th->uid(), iph->saddr(), iph->sport(), iph->daddr(), iph->dport(), tcph->hlen(), datalen, tcph->seqno(), tcph->ackno(), tcph->flags(), flagstr(tcph->flags()), tcph->sa_length(), tcph->reason());}char *FullTcpAgent::flagstr(int hflags){ // update this if tcp header flags change static char *flagstrs[28] = { "<null>", "<FIN>", "<SYN>", "<SYN,FIN>", // 0-3 "<?>", "<?,FIN>", "<?,SYN>", "<?,SYN,FIN>", // 4-7 "<PSH>", "<PSH,FIN>", "<PSH,SYN>", "<PSH,SYN,FIN>", // 0x08-0x0b /* do not use <??, in next line because that's an ANSI trigraph */ "<?>", "<?,FIN>", "<?,SYN>", "<?,SYN,FIN>", // 0x0c-0x0f "<ACK>", "<ACK,FIN>", "<ACK,SYN>", "<ACK,SYN,FIN>", // 0x10-0x13 "<ACK>", "<ACK,FIN>", "<ACK,SYN>", "<ACK,SYN,FIN>", // 0x14-0x17 "<PSH,ACK>", "<PSH,ACK,FIN>", "<PSH,ACK,SYN>", "<PSH,ACK,SYN,FIN>", // 0x18-0x1b }; if (hflags < 0 || (hflags > 28)) { /* Added strings for CWR and ECE -M. Weigle 6/27/02 */ if (hflags == 72) return ("<ECE,PSH>"); else if (hflags == 80) return ("<ECE,ACK>"); else if (hflags == 88) return ("<ECE,PSH,ACK>"); else if (hflags == 152) return ("<CWR,PSH,ACK>"); else if (hflags == 153) return ("<CWR,PSH,ACK,FIN>"); else return ("<invalid>"); } return (flagstrs[hflags]);}char *FullTcpAgent::statestr(int state){ static char *statestrs[TCP_NSTATES] = { "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", "LAST_ACK", "FIN_WAIT_2" }; if (state < 0 || (state >= TCP_NSTATES)) return ("INVALID"); return (statestrs[state]);}voidDelAckTimer::expire(Event *) { a_->timeout(TCP_TIMER_DELACK);}/* * reset to starting point, don't set state_ here, * because our starting point might be LISTEN rather * than CLOSED if we're a passive opener */voidFullTcpAgent::reset(){ cancel_timers(); // cancel timers first TcpAgent::reset(); // resets most variables rq_.clear(); // clear reassembly queue rtt_init(); // zero rtt, srtt, backoff last_ack_sent_ = -1; rcv_nxt_ = -1; pipe_ = 0; rtxbytes_ = 0; flags_ = 0; t_seqno_ = iss_; maxseq_ = -1; irs_ = -1; last_send_time_ = -1.0; if (ts_option_) recent_ = recent_age_ = 0.0; else recent_ = recent_age_ = -1.0; fastrecov_ = FALSE;}/* * This function is invoked when the connection is done. It in turn * invokes the Tcl finish procedure that was registered with TCP. * This function mimics tcp_close() */voidFullTcpAgent::finish(){ Tcl::instance().evalf("%s done", this->name());}/* * headersize: * how big is an IP+TCP header in bytes; include options such as ts * this function should be virtual so others (e.g. SACK) can override */intFullTcpAgent::headersize(){ int total = tcpip_base_hdr_size_; if (total < 1) { fprintf(stderr, "%f: FullTcpAgent(%s): warning: tcpip hdr size is only %d bytes\n", now(), name(), tcpip_base_hdr_size_); } if (ts_option_) total += ts_option_size_; return (total);}/* * flags that are completely dependent on the tcp state * these are used for the next outgoing packet in foutput() * (in real TCP, see tcp_fsm.h, the "tcp_outflags" array) */intFullTcpAgent::outflags(){ // in real TCP an RST is added in the CLOSED state static int tcp_outflags[TCP_NSTATES] = { TH_ACK, /* 0, CLOSED */ 0, /* 1, LISTEN */ TH_SYN, /* 2, SYN_SENT */ TH_SYN|TH_ACK, /* 3, SYN_RECEIVED */ TH_ACK, /* 4, ESTABLISHED */ TH_ACK, /* 5, CLOSE_WAIT */ TH_FIN|TH_ACK, /* 6, FIN_WAIT_1 */ TH_FIN|TH_ACK, /* 7, CLOSING */ TH_FIN|TH_ACK, /* 8, LAST_ACK */ TH_ACK, /* 9, FIN_WAIT_2 */ /* 10, TIME_WAIT --- not used in simulator */ }; if (state_ < 0 || (state_ >= TCP_NSTATES)) { fprintf(stderr, "%f FullTcpAgent(%s): invalid state %d\n", now(), name(), state_); return (0x0); } return (tcp_outflags[state_]);}/* * reaass() -- extract the appropriate fields from the packet * and pass this info the ReassemblyQueue add routine * * returns the TCP header flags representing the "or" of * the flags contained in the adjacent sequence # blocks */intFullTcpAgent::reass(Packet* pkt){ hdr_tcp *tcph = hdr_tcp::access(pkt); hdr_cmn *th = hdr_cmn::access(pkt); int start = tcph->seqno(); int end = start + th->size() - tcph->hlen(); int tiflags = tcph->flags(); int fillshole = (start == rcv_nxt_); int flags; // end contains the seq of the last byte of // in the packet plus one if (start == end && (tiflags & TH_FIN) == 0) { fprintf(stderr, "%f: FullTcpAgent(%s)::reass() -- bad condition - adding non-FIN zero-len seg\n", now(), name()); abort(); } flags = rq_.add(start, end, tiflags, 0); //present: // // If we've never received a SYN (unlikely) // or this is an out of order addition, no reason to coalesce // if (TCPS_HAVERCVDSYN(state_) == 0 || !fillshole) { return (0x00); } // // If we get some data in SYN_RECVD, no need to present to user yet // if (state_ == TCPS_SYN_RECEIVED && (end > start)) return (0x00); // clear out data that has been passed, up to rcv_nxt_, // collects flags flags |= rq_.cleartonxt(); return (flags);}/* * utility function to set rcv_next_ during inital exchange of seq #s */intFullTcpAgent::rcvseqinit(int seq, int dlen){ return (seq + dlen + 1);}/* * build a header with the timestamp option if asked */intFullTcpAgent::build_options(hdr_tcp* tcph){ int total = 0; if (ts_option_) { tcph->ts() = now(); tcph->ts_echo() = recent_; total += ts_option_size_; } else { tcph->ts() = tcph->ts_echo() = -1.0; } return (total);}/* * pack() -- is the ACK a partial ACK? (not past recover_) */intFullTcpAgent::pack(Packet *pkt){ hdr_tcp *tcph = hdr_tcp::access(pkt); /* Added check for fast recovery. -M. Weigle 5/2/02 */ return (fastrecov_ && tcph->ackno() >= highest_ack_ && tcph->ackno() < recover_);}/* * baseline reno TCP exists fast recovery on a partial ACK */voidFullTcpAgent::pack_action(Packet*){ if (reno_fastrecov_ && fastrecov_ && cwnd_ > double(ssthresh_)) { cwnd_ = double(ssthresh_); // retract window if inflated } fastrecov_ = FALSE;//printf("%f: EXITED FAST RECOVERY\n", now()); dupacks_ = 0;}/* * ack_action -- same as partial ACK action for base Reno TCP */voidFullTcpAgent::ack_action(Packet* p){ FullTcpAgent::pack_action(p);}/* * sendpacket: * allocate a packet, fill in header fields, and send * also keeps stats on # of data pkts, acks, re-xmits, etc * * fill in packet fields. Agent::allocpkt() fills * in most of the network layer fields for us. * So fill in tcp hdr and adjust the packet size. * * Also, set the size of the tcp header. */voidFullTcpAgent::sendpacket(int seqno, int ackno, int pflags, int datalen, int reason){ Packet* p = allocpkt(); hdr_tcp *tcph = hdr_tcp::access(p); hdr_flags *fh = hdr_flags::access(p); /* build basic header w/options */ tcph->seqno() = seqno; tcph->ackno() = ackno; tcph->flags() = pflags; tcph->reason() |= reason; // make tcph->reason look like ns1 pkt->flags? tcph->sa_length() = 0; // may be increased by build_options() tcph->hlen() = tcpip_base_hdr_size_; tcph->hlen() += build_options(tcph); /* * Explicit Congestion Notification (ECN) related: * Bits in header: * ECT (EC Capable Transport), * ECNECHO (ECHO of ECN Notification generated at router), * CWR (Congestion Window Reduced from RFC 2481) * States in TCP: * ecn_: I am supposed to do ECN if my peer does * ect_: I am doing ECN (ecn_ should be T and peer does ECN) */ // set ect on data packets (not syn or ack packets) if ( datalen > 0 && ecn_ ){ fh->ect() = ect_; // on after mutual agreement on ECT } else { /* Set ect() to 0. -M. Weigle 1/19/05 */ fh->ect() = 0; } // fill in CWR and ECE bits which don't actually sit in // the tcp_flags but in hdr_flags if ( pflags & TH_ECE) { fh->ecnecho() = 1; } else { fh->ecnecho() = 0; } if ( pflags & TH_CWR ) { fh->cong_action() = 1; } else { /* Set cong_action() to 0 -M. Weigle 1/19/05 */ fh->cong_action() = 0; } /* actual size is data length plus header length */ hdr_cmn *ch = hdr_cmn::access(p); ch->size() = datalen + tcph->hlen(); if (datalen <= 0) ++nackpack_; else { ++ndatapack_; ndatabytes_ += datalen; last_send_time_ = now(); // time of last data } if (reason == REASON_TIMEOUT || reason == REASON_DUPACK || reason == REASON_SACK) { ++nrexmitpack_; nrexmitbytes_ += datalen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -