📄 tcp_input.pc
字号:
tp->t_flags |= TF_DELACK; tp->rcv_nxt += ti->ti_len; tiflags = ti->ti_flags & TH_FIN; submit_data(node, inp->app_proto_type, inp->con_id, (unsigned char *)(ti + 1), ti->ti_len, tp); pc_free(tcp_seg); } else { tiflags = tcp_reass(node, tp, ti, tcp_stat); tp->t_flags |= TF_ACKNOW; } } else { if (ti->ti_seq == tp->rcv_nxt && tp->seg_next == (struct tcpiphdr *)tp && tp->t_state == TCPS_ESTABLISHED) { tp->t_flags |= TF_DELACK; (tp)->rcv_nxt += (ti)->ti_len; tiflags = (ti)->ti_flags & TH_FIN; submit_data(node, inp->app_proto_type, inp->con_id, datap, ti->ti_len, tp); pc_free(tcp_seg); } else { tiflags = tcp_reass(node, tp, ti, tcp_stat); tp->t_flags |= TF_ACKNOW; } } /* * Note the amount of data that peer has sent into * our window, in order to estimate the sender's * buffer size. */ len = inp->inp_rcv_hiwat - (tp->rcv_adv - tp->rcv_nxt); } else { pc_free(tcp_seg); tiflags &= ~TH_FIN; } /* * If FIN is received ACK the FIN and let the user know * that the connection is closing. */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * If connection is half-synchronized * (ie NEEDSYN flag on) then delay ACK, * so it may be piggybacked when SYN is sent. * Otherwise, since we received a FIN then no * more input can be expected, send ACK now. */ if (tp->t_flags & TF_NEEDSYN) tp->t_flags |= TF_DELACK; else tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch (tp->t_state) { /* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; break; /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. */ case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; break; /* * In FIN_WAIT_2 state enter the TIME_WAIT state, * starting the time-wait timer, turning off the other * standard timers. */ case TCPS_FIN_WAIT_2: tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; /* * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; } } /* * Return any desired output. */ if (needoutput || (tp->t_flags & TF_ACKNOW)){ tcp_output(node, tp, tcp_now, tcp_stat); } return;dropafterack: /* * Generate an ACK dropping incoming segment if it occupies * sequence space, where the ACK reflects our state. */ if (tiflags & TH_RST) goto drop; tp->t_flags |= TF_ACKNOW; pc_free(tcp_seg); tcp_output(node, tp, tcp_now, tcp_stat); return;dropwithreset: /* * ADDED by Ken. Problem occurs when server already closes connection * while client is still sending or vice versa. If this happens, * tp == NULL. Just do nothing and return in this case. */ if (tp == NULL) { pc_free(tcp_seg); return; } /* * Generate a RST, dropping incoming segment. * Make ACK acceptable to originator of segment. * Don't bother to respond if destination was broadcast/multicast. */ if (tiflags & TH_RST) goto drop; if (tiflags & TH_ACK){ tcp_respond(node, tp, ti, 1, (tcp_seq)0, ti->ti_ack, TH_RST, tcp_stat); } else { if (tiflags & TH_SYN) ti->ti_len++; tcp_respond(node, tp, ti, 1, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK, tcp_stat); } pc_free(tcp_seg); return;drop: /* * Drop space held by incoming segment and return. */ pc_free(tcp_seg); return;}static voidtcp_dooptions(tp, cp, cnt, ti, topt, tcp_now, tcp_stat) struct tcpcb *tp; unsigned char *cp; int cnt; struct tcpiphdr *ti; struct tcpopt *topt; unsigned long tcp_now; struct tcpstat *tcp_stat;{ unsigned short mss = 0; int opt, optlen; unsigned char *optp = cp; unsigned char *datap = cp + cnt; if (cnt==0) return; for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == TCPOPT_EOL) break; if (opt == TCPOPT_NOP) optlen = 1; else { optlen = cp[1]; if (optlen <= 0) break; } switch (opt) { default: continue; case TCPOPT_MAXSEG: if (optlen != TCPOLEN_MAXSEG) continue; if (!(ti->ti_flags & TH_SYN)) continue; memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); break; case TCPOPT_WINDOW: if (optlen != TCPOLEN_WINDOW) continue; if (!(ti->ti_flags & TH_SYN)) continue; tp->t_flags |= TF_RCVD_SCALE; tp->requested_s_scale = MIN(cp[2], TCP_MAX_WINSHIFT); break; case TCPOPT_TIMESTAMP: if (optlen != TCPOLEN_TIMESTAMP) continue; topt->to_flag |= TOF_TS; memcpy((char *)&topt->to_tsval, (char *)cp + 2, sizeof(topt->to_tsval)); memcpy((char *)&topt->to_tsecr, (char *)cp + 6, sizeof(topt->to_tsecr)); /* * A timestamp received in a SYN makes * it ok to send timestamp requests and replies. */ if (ti->ti_flags & TH_SYN) { tp->t_flags |= TF_RCVD_TSTMP; tp->ts_recent = topt->to_tsval; tp->ts_recent_age = tcp_now; } break; } } if (ti->ti_flags & TH_SYN) tcp_mss(tp, mss, tcp_stat); /* sets t_maxseg */ /* remove options */ memcpy(optp, datap, ti->ti_len);}/* * Collect new round-trip time estimate * and update averages and current timeout. */static voidtcp_xmit_timer(tp, rtt, tcp_stat) struct tcpcb *tp; int rtt; struct tcpstat *tcp_stat;{ int delta; tp->t_rttupdated++; if (tp->t_srtt != 0) { /* * srtt is stored as fixed point with 5 bits after the * binary point (i.e., scaled by 8). The following magic * is equivalent to the smoothing algorithm in rfc793 with * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed * point). Adjust rtt to origin 0. */ delta = ((rtt - 1) << TCP_DELTA_SHIFT) - (tp->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)); if ((tp->t_srtt += delta) <= 0) tp->t_srtt = 1; /* * We accumulate a smoothed rtt variance (actually, a * smoothed mean difference), then set the retransmit * timer to smoothed rtt + 4 times the smoothed variance. * rttvar is stored as fixed point with 4 bits after the * binary point (scaled by 16). The following is * equivalent to rfc793 smoothing with an alpha of .75 * (rttvar = rttvar*3/4 + |delta| / 4). This replaces * rfc793's wired-in beta. */ if (delta < 0) delta = -delta; delta -= tp->t_rttvar >> (TCP_RTTVAR_SHIFT - TCP_DELTA_SHIFT); if ((tp->t_rttvar += delta) <= 0) tp->t_rttvar = 1; } else { /* * No rtt measurement yet - use the unsmoothed rtt. * Set the variance to half the rtt (so our first * retransmit happens at 3*rtt). */ tp->t_srtt = rtt << TCP_RTT_SHIFT; tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); } tp->t_rtt = 0; tp->t_rxtshift = 0; /* * the retransmit should happen at rtt + 4 * rttvar. * Because of the way we do the smoothing, srtt and rttvar * will each average +1/2 tick of bias. When we compute * the retransmit timer, we want 1/2 tick of rounding and * 1 extra tick because of +-1/2 tick uncertainty in the * firing of the timer. The bias will give us exactly the * 1.5 tick we need. But, because the bias is * statistical, we have to test that we don't drop below * the minimum feasible timer (which is 2 ticks). */ TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), MAX(tp->t_rttmin, rtt + 2), TCPTV_REXMTMAX); /* * We received an ack for a packet that wasn't retransmitted; * it is probably safe to discard any error indications we've * received recently. This isn't quite right, but close enough * for now (a route might have failed after we sent a segment, * and the return path might not be symmetrical). */ tp->t_softerror = 0; if (tcp_stat) tcp_stat->tcps_rttupdated++;}/* * Determine a reasonable value for maxseg size. * If the route is known, check route for mtu. * If none, use an mss that can be handled on the outgoing * interface without forcing IP to fragment; if bigger than * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES * to utilize large mbufs. If no route is found, route has no mtu, * or the destination isn't local, use a default, hopefully conservative * size (usually 512 or the default IP max size, but no more than the mtu * of the interface), as we can't discover anything about intervening * gateways or networks. We also initialize the congestion/slow start * window to be a single segment if the destination isn't local. * While looking at the routing entry, we also initialize other path-dependent * parameters from pre-set or cached values in the routing entry. * * Also take into account the space needed for options that we * send regularly. Make maxseg shorter by that amount to assure * that we can send maxseg amount of data even when the options * are present. Store the upper limit of the length of options plus * data in maxopd. * * NOTE that this routine is only called when we process an incoming * segment, for outgoing segments only tcp_mssopt is called. * */static voidtcp_mss(tp, offer, tcp_stat) struct tcpcb *tp; int offer; struct tcpstat *tcp_stat;{ int mss; unsigned long bufsize; struct inpcb *inp = tp->t_inpcb; /* * Offer == 0 means that there was no MSS on the SYN segment, * in this case we use TCP_MSS. */ if (offer == 0) offer = TCP_MSS; else /* * Sanity check: make sure that maxopd will be large * enough to allow some data on segments even is the * all the option space is used (40bytes). Otherwise * funny things may happen in tcp_output. */ offer = MAX(offer, 64); mss = MIN(tp->t_maxseg, offer); /* * If there's a pipesize, change the socket buffer to that size. * if the mss is larger than the buffer size, derease the mss. */ bufsize = inp->inp_snd.hiwat; if (bufsize < mss) mss = bufsize; /* * maxopd stores the maximum length of data AND options * in a segment; maxseg is the amount of data in a normal * segment. We need to store this value (maxopd) apart * from maxseg, because now every segment carries options * and thus we normally have somewhat less data in segments. */ tp->t_maxopd = mss; if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) mss -= TCPOLEN_TSTAMP_APPA; tp->t_maxseg = mss; tp->snd_cwnd = mss;}/* * Determine the MSS option to send on an outgoing SYN. */inttcp_mssopt(){ return TCP_MSS;}/* * Deliver data to application. */static voidsubmit_data(node, app_type, conn_id, datap, length, tp) GlomoNode *node; APP_TYPE app_type; int conn_id; unsigned char *datap; int length; struct tcpcb *tp;{ Message *msg; TransportToAppDataReceived *tcpDataReceived; GlomoTransportTcp *tcpLayer = node->transportData.tcp; if (length > 0) { msg = GLOMO_MsgAlloc(node, GLOMO_APP_LAYER, app_type, MSG_APP_FromTransDataReceived); GLOMO_MsgInfoAlloc(node, msg, sizeof(TransportToAppDataReceived)); tcpDataReceived = (TransportToAppDataReceived *) msg->info; tcpDataReceived->connectionId = conn_id; GLOMO_MsgPacketAlloc(node, msg, length); memcpy(msg->packet, datap, length); GLOMO_MsgSend(node, msg, TRANSPORT_DELAY); tcpLayer->tp = tp; TransportTcpSetTimerForOutput(node); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -