📄 tcp-sock.cc
字号:
/* * If we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but * transmit timer is running and timed sequence * number was acked, update smoothed round trip time. * Since we now have an rtt measurement, cancel the * timer backoff (cf., Phil Karn's retransmit alg.). * Recompute the initial retransmit timer. * * If all outstanding data is acked, stop retransmit * If there is more data to be acked, restart retransmit * timer, using current (possibly backed-off) value. */ newack(pkt); // handle timers, update highest_ack_ --pipe_; /* * if this is a partial ACK, invoke whatever we should */ int partial = pack(pkt); if (partial) pack_action(pkt); else ack_action(pkt); /* * if this is an ACK with an ECN indication, handle this */ if (fh->ecnecho()) ecn(highest_ack_); // updated by newack(), above // CHECKME: handling of rtx timer if (ackno == maxseq_) { needoutput = TRUE; } /* * If no data (only SYN) was ACK'd, * skip rest of ACK processing. */ if (ackno == (highest_ack_ + 1)) goto step6; // if we are delaying initial cwnd growth (probably due to // large initial windows), then only open cwnd if data has // been received /* * When new data is acked, open the congestion window. * If the window gives us less than ssthresh packets * in flight, open exponentially (maxseg per packet). * Otherwise open about linearly: maxseg per window * (maxseg^2 / cwnd per packet). */ if ((!delay_growth_ || (rcv_nxt_ > 0)) && last_state_ == TCPS_ESTABLISHED) { if (!partial || open_cwnd_on_pack_) opencwnd(); } // K: added state check in equal but diff way if ((state_ >= TCPS_FIN_WAIT_1) && (ackno == maxseq_)) { ourfinisacked = TRUE; } else { ourfinisacked = FALSE; } // additional processing when we're in special states switch (state_) { /* * In FIN_WAIT_1 STATE in addition to the processing * for the ESTABLISHED state if our FIN is now acknowledged * then enter FIN_WAIT_2. */ case TCPS_FIN_WAIT_1: /* doing active close */ if (ourfinisacked) { // got the ACK, now await incoming FIN newstate(TCPS_FIN_WAIT_2); cancel_timers(); needoutput = FALSE; } break; /* * In CLOSING STATE in addition to the processing for * the ESTABLISHED state if the ACK acknowledges our FIN * then enter the TIME-WAIT state, otherwise ignore * the segment. */ case TCPS_CLOSING: /* simultaneous active close */; if (ourfinisacked) { newstate(TCPS_CLOSED); cancel_timers(); } break; /* * In LAST_ACK, we may still be waiting for data to drain * and/or to be acked, as well as for the ack of our FIN. * If our FIN is now acknowledged, * enter the closed state and return. */ case TCPS_LAST_ACK: /* passive close */ // K: added state change here if (ourfinisacked) { newstate(TCPS_CLOSED);#ifdef notdefcancel_timers(); // DOES THIS BELONG HERE?, probably (see tcp_cose#endif finish(); reset(); goto drop; } else { // should be a FIN we've seen hdr_ip* iph = hdr_ip::access(pkt); fprintf(stderr, "%f: %d.%d>%d.%d FullTcpAgent::recv(%s) received non-ACK (state:%d)\n", now(), iph->saddr(), iph->sport(), iph->daddr(), iph->dport(), name(), state_); } break; /* no case for TIME_WAIT in simulator */ } // inner switch } // outer switchstep6: /* real TCP handles window updates and URG data here *//* dodata: this label is in the "real" code.. here only for reference */ /* * DATA processing */ if ((datalen > 0 || (tiflags & TH_FIN)) && TCPS_HAVERCVDFIN(state_) == 0) { if (tcph->seqno() == rcv_nxt_ && rq_.empty()) { // see the "TCP_REASS" macro for this code: // got the in-order packet we were looking // for, nobody is in the reassembly queue, // so this is the common case... // note: in "real" TCP we must also be in // ESTABLISHED state to come here, because // data arriving before ESTABLISHED is // queued in the reassembly queue. Since we // don't really have a process anyhow, just // accept the data here as-is (i.e. don't // require being in ESTABLISHED state) flags_ |= TF_DELACK; PktDataEntry *pe = new PktDataEntry(rcv_nxt_, (PacketData *)pkt->userdata()); rcv_buf_.append(pe); rcv_nxt_ += datalen; rcv_wnd_ -= datalen; if(pkt->userdata() && datalen) { if(datalen==((PacketData *)pkt->userdata())->size()) recvBytes(datalen); // notify app. of "delivery" } tiflags = tcph->flags() & TH_FIN; needoutput = TRUE; } else { // see the "tcp_reass" function: // not the one we want next (or it // is but there's stuff on the reass queue); // do whatever we need to do for out-of-order // segments or hole-fills. Also, // send an ACK to the other side right now. // K: some changes here, figure out int rcv_nxt_old_ = rcv_nxt_; // notify app. if changes tiflags = reass(pkt); PktDataEntry *pe = new PktDataEntry(tcph->seqno(), (PacketData *)pkt->userdata()); insert(&rcv_buf_, pe); if (rcv_nxt_ > rcv_nxt_old_) recvBytes(rcv_nxt_ - rcv_nxt_old_); if(datalen && app_) ((NSSocket *)app_)->upcall_recv((PacketData*)pkt->userdata()); if (tiflags & TH_PUSH) { // K: APPLICATION recv needoutput = need_send(); } else { flags_ |= TF_ACKNOW; } } } else { /* * we're closing down or this is a pure ACK that * wasn't handled by the header prediction part above * (e.g. because cwnd < wnd) */ // K: this is deleted tiflags &= ~TH_FIN; } /* * if FIN is received, ACK the FIN * (let user know if we could do so) */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(state_) == 0) { flags_ |= TF_ACKNOW; rcv_nxt_++; } if(app_) app_->upcall_closing(); switch (state_) { /* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. * (passive close) */ case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: newstate(TCPS_CLOSE_WAIT); break; /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. * (simultaneous close) */ case TCPS_FIN_WAIT_1: newstate(TCPS_CLOSING); break; /* * In FIN_WAIT_2 state enter the TIME_WAIT state, * starting the time-wait timer, turning off the other * standard timers. * (in the simulator, just go to CLOSED) * (completion of active close) */ case TCPS_FIN_WAIT_2: newstate(TCPS_CLOSED); cancel_timers(); break; } } /* end of if FIN bit on */ if (needoutput || (flags_ & TF_ACKNOW)) send_much(1, REASON_NORMAL, maxburst_); else if (curseq_ >= highest_ack_ || infinite_send_) send_much(0, REASON_NORMAL, maxburst_); // K: which state to return to when nothing left? if (!halfclose_ && state_ == TCPS_CLOSE_WAIT && highest_ack_ == maxseq_) usrclosed(); Packet::free(pkt); // haoboy: Is here the place for done{} of active close? // It cannot be put in the switch above because we might need to do // send_much() (an ACK) if (state_ == TCPS_CLOSED) Tcl::instance().evalf("%s done", this->name()); return;dropafterack: flags_ |= TF_ACKNOW; send_much(1, REASON_NORMAL, maxburst_); goto drop;dropwithreset: /* we should be sending an RST here, but can't in simulator */ if (tiflags & TH_ACK) { sendpacket(ackno, 0, 0x0, 0, NULL, REASON_NORMAL); } else { int ack = tcph->seqno() + datalen; if (tiflags & TH_SYN) ack--; sendpacket(0, ack, TH_ACK, 0, NULL, REASON_NORMAL); }drop: Packet::free(pkt); return;}voidSocketTcp::sendpacket(int seqno, int ackno, int pflags, int datalen, PacketData *data, int reason){ Packet* p = allocpkt(datalen); hdr_tcp *tcph = hdr_tcp::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); tcph->advwin() = rcv_wnd_; /* ECT, ECN, and congestion action */ hdr_flags *fh = hdr_flags::access(p); fh->ect() = ect_; // on after mutual agreement on ECT if (ecn_ && !ect_) // initializing; ect = 0, ecnecho = 1 fh->ecnecho() = 1; else { fh->ecnecho() = recent_ce_; } fh->cong_action() = cong_action_; /* 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(data) { p->setdata(data->copy()); }else { fprintf(stderr, "datalen>0 without data\n"); } } if (reason == REASON_TIMEOUT || reason == REASON_DUPACK) { ++nrexmitpack_; nrexmitbytes_ += datalen; } last_ack_sent_ = ackno; send(p, 0);}int SocketTcp::r_advance_bytes(int nb) { int new_inc = nb, old_curseq = curseq_; // // state-specific operations: // if CLOSED, reset and try a new active open/connect // if ESTABLISHED, just try to send more // if above ESTABLISHED, we are closing, so don't allow // if anything else (establishing), do nothing here // if (state_ > TCPS_ESTABLISHED) { fprintf(stderr, "%f: SocketTcpAgent::advance(%s): cannot advance while in state %d\n", now(), name(), state_); return 0; } else if (state_ == TCPS_CLOSED) { reset(); curseq_ = iss_ + nb; connect(); // initiate new connection } else if (state_ == TCPS_ESTABLISHED) { closed_ = 0; if (curseq_ < iss_) curseq_ = iss_; curseq_ = curseq_ + nb > (highest_ack_ + snd_wnd_)? highest_ack_+ snd_wnd_: curseq_+nb; new_inc = curseq_ - old_curseq; send_much (0, REASON_NORMAL, maxburst_); } return new_inc; }int SocketTcp::r_advance_pkt(PacketData *p) { int new_inc = 0, old_curseq = curseq_, nb; if(p==NULL) return 0; nb = p->size(); if (state_ > TCPS_ESTABLISHED) { fprintf(stderr, "%f: SocketTcpAgent::advance(%s %d): cannot advance while in state %d\n", now(), name(), here_.addr_, state_); // socket is closed return -1; } else if (state_ == TCPS_CLOSED) { reset(); PktDataEntry *pe = new PktDataEntry((int)curseq_+1, p); curseq_ += nb; snd_buf_.append(pe); connect(); // initiate new connection return 0; } else if (state_ == TCPS_ESTABLISHED) { closed_ = 0; if (curseq_ < iss_) curseq_ = iss_; curseq_ = curseq_ + nb > (highest_ack_ + snd_wnd_)? (int)curseq_: curseq_ + nb; new_inc = curseq_ - old_curseq; if(new_inc) { PktDataEntry *pe = new PktDataEntry(old_curseq + 1, p); apcnt++; snd_buf_.append(pe); } send_much(0, REASON_NORMAL, maxburst_); } if (new_inc && curseq_ + nb <= highest_ack_ + snd_wnd_) return 1; if (new_inc && curseq_ + nb > highest_ack_ + snd_wnd_) return 0; if(p!=NULL) { dropcnt++; } return -1;}void SocketTcp::listen(int max) { FullTcpAgent::listen(); max_conn_ = max; listen_only_ = TRUE;}void SocketTcp::ack_syn(Packet *synpkt) { hdr_tcp *tcph = hdr_tcp::access(synpkt); irs_ = tcph->seqno(); t_seqno_ = iss_; /* tcp_sendseqinit() macro in real tcp */ rcv_nxt_ = rcvseqinit(irs_, 0); flags_ |= TF_ACKNOW; newstate(TCPS_SYN_RECEIVED); send_much(1, REASON_NORMAL, maxburst_); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -