⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpnetd.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* If the sending of selective acknowledgements is enabled, then before sending	   the ACK we are about to send, update our list of SACK blocks according to	   the sequence number rance of the message we are about to add to the holding	   queue, so that the ACK will include an up-to-date list of SACK blocks. */	if (svp->sv_flags2 & SV_OUT_SACKS_ENABLED) {		tcp_add_out_sack_block(svp,seqno,length);	} /* if */#endif /* TCP_SELACK_ENHANCEMENTS */    /* Send an immediate "duplicate" ACK here (cancelling the delayed ack that 	   was scheduled earlier before we knew this was an out-of-order segment), 	   to facilitate "fast retransmit" if the peer has that enabled. */    tcp_sndack(mp, svp);    return (st)smhqin;} /* tcp_net_deliver *//*************************************************************************                                                                       **  Function :                                                           **                                                                       **  Description :                                                        **                                                                       **                                                                       **  Parameters : None.                                                   **                                                                       **  Return : None.                                                       **                                                                       *************************************************************************//* Accept this packet (as if) from the network */pflocal st  tcp_naccept (fast m * mp){    fast    tcpsv_t * svp;    fast    TCPH_T  * tcphp;    u16     flags;    if ((svp = mp->m_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_naccept: no state vector\n");        return (st)mp->m_dispfn;    }    tcphp = (TCPH_T *)mp->m_cp;    flags =  NetToHost16(&tcphp[TCPH_FLAGS]);    mp->m_hp = (char *)tcphp + tcphl(tcphp);    smcritical(mp);/* NOTE: The processing of this packet is in a critical section from *  this point on;  this guarantees that the ordering of state *  updates will be the same as that of receive queue insertion; */    /* The following assert seems is for the purpose of making sure that this segment 	   contains the "next expected sequence number" within it. Supposedly we couldn't	   get here if it didn't. */    assert(MC32U(svp->sv_rnxt, >=, NetToHost32(&tcphp[TCPH_SEQNO])), "tcp_naccept: bad seqno\n");    /* Skip over any data at the beginning of the segment which we may have already       "accepted" -- e.g., this could be retransmitted data  which contains some       data we already have. */    /* In the process, if this segment contains an urgent pointer, adjust it according to	   how much data we skip over. If we skip past the urgent pointer, turn off the	   urgent flag and zero the urgent pointer */		{     int adjust_hp = ( MU32(svp->sv_rnxt) - NetToHost32(&tcphp[TCPH_SEQNO]) );     mp->m_hp += adjust_hp;	 if (URG_ON(flags)) { 		u16 urgoff = NetToHost16(&tcphp[TCPH_URGENT]);		if (adjust_hp >= urgoff) {			urgoff = 0;			flags &= ~URG;            HostToNet16(&tcphp[TCPH_FLAGS], flags);		} else {			urgoff -= adjust_hp;		}        HostToNet16(&tcphp[TCPH_URGENT], urgoff);	 } /* if urgent flag set */	}    /* The following check is to make sure that the entire segment doesn't already 	   contain data that we've already previously accepted, i.e. it could be a 	   retransmitted segment and we've already seen the original segment */    if (mp->m_hp > mp->m_tp &&       (FIN_OFF(flags)  ||  mp->m_hp - 1 != mp->m_tp))    {        trace2(tcp_thq, "tcp_naccept: seq 0x%x oldie; rnxt 0x%x\n", NetToHost32(&tcphp[TCPH_SEQNO]), MU32(svp->sv_rnxt));        return (st)mp->m_dispfn;    }    /* Extract any out-of-band data from the segment before queuing the in-band       data to the socket */    tcp_urgdata(mp);    /* After any trimming we may have done above, does the segment still have	   any data to accept into the recieve buffer? */    if (tcp_dl(mp)) {   /* Yes -- stick it where it counts */        assert(mp->m_dispfn == smdispose, "tcp_naccept: non-trivial dispfn\n");        if (mp->m_sop == (so_t *)0) {			/* But we've lost the socket... */            debug0(tcp_debug  &&  m_dsize(mp), "tcp_naccept: no socket for smrqin (lost real data)\n");            /* there's more to life than this */            return (st)tcp_nstate;        }        mp->m_dispfn = tcp_nstate;  /* state update functions */		/* MBM note: tcp_nstate will look in the holding queue for previously-received		   out of order data that can now be acked due to the in-order data we just		   received and are about to put into the socket receive buffer */        /***** MBM note: the following lines were removed from here because it was seen		 that, if the receive queue is empty at this time, and between the time we		 set the F_SO_SHUTDOWN flag and invoke smrqin, the application task interrupts		 and does a "recv", the application will get returned an error (FNS_ESHUTDOWN		 from fns_recvfrom). It seems to me that the F_SO_SHUTDOWN flag shouldn't be set		 until the data from this segment is in the receive queue and the empty "EOF" 		 message in the receive queue. So I am moving the following code into "tcp_finpkt"		 which puts the empty "EOF" message into the receive queue. */#if 0#ifndef WSI1_ONLY        if (FIN_ON(NetToHost16(&tcphp[TCPH_FLAGS]))) {            mp->m_sop->so_flags |= F_SO_RSHUTDOWN;		}#endif /* WSI1_ONLY */#endif        return (st)smrqin;    }    assert(m_dsize(mp) == 0, "tcp_naccept: non-0 m_dsize\n");    return (st)tcp_nstate;  /* just update ACK's & such */} /* tcp_naccept *//*************************************************************************                                                                       **  Function :                                                           **                                                                       **  Description :                                                        **                                                                       **                                                                       **  Parameters : None.                                                   **                                                                       **  Return : None.                                                       **                                                                       *************************************************************************//* Update socket state after 'tcp_naccept'. If this packet contains data or * a FIN bit, then call will be as a dispose function after 'smrqin' and * the 'm_dispfn' will have been set to smnil; otherwise it is called * directly by the state machine and the 'm_dispfn' will still be 'smdispose' * (this latter case occurs on ACKnowledgement-only packets). *//* THIS WHOLE FUNCTION RUNS IN CRITICAL SECTION DUE TO THE 'smcritical' * IN 'tcp_naccept' (above) */pflocal st  tcp_nstate (fast m * mp){    fast    tcpsv_t * svp;    fast    TCPH_T  * tcphp;    fast    u16 flags;    fast    u32 seqno;    fast    u32 ackno;    fast    so_t    * sop;    int length;    if (mp->m_err) {        /* more here? --msd */        return (st)mp->m_dispfn;    }    trace0(tcp_trcv, "tcp_nstate: packet into receive queue\n");    if ((svp = mp->m_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_nstate: no state vector\n");        return (st)mp->m_dispfn;    }    tcphp = (TCPH_T *)mp->m_cp;    ackno = NetToHost32(&tcphp[TCPH_ACKNO]);    seqno = NetToHost32(&tcphp[TCPH_SEQNO]);    flags = NetToHost16(&tcphp[TCPH_FLAGS]);    if (FIN_ON(flags))  /* generate EOF */        tcp_finpkt(mp, svp);    length = tcp_dl(mp) + mp->m_oob;    M32U(svp->sv_rnxt, =, seqno + length );#ifdef TCP_SELACK_ENHANCEMENTS    /* If we are sending SACKS, adjust our SACK list according to the data	   just absorbed into the receive buffer */	if (svp->sv_flags2 & SV_OUT_SACKS_ENABLED) {       tcp_adjust_out_sack_blocks_for_rnxt(svp);	}#endif /* TCP_SELACK_ENHANCEMENTS */ 	if (URG_ON(flags)) {       tcp_urgstate(mp); /* look for urgent information */    }    switch (svp->sv_state) {      case ESTAB:        if ((svp->sv_flags & SV_RFINFLG)  ||  FIN_ON(flags)) {            /* FIN seen */            svp->sv_flags |= SV_RFINFLG;            /* This must be the only place state is set             * to CLOSE_WAIT */            set_state("tcp_nstate", svp, CLOSE_WAIT);#ifdef TCP_TRANSACTION_TCP 			/* If this is a transaction TCP connection and we are the passive			   side and have delivered data to the application and we are 			   delaying our SYN-ACK to give the application time to form and send 			   a response, don't do the "no_more_data_in" right now because that 			   will generate an immediate ACK in lieu of the delayed one which			   has been scheduled */            if (!(TRANSACTION_DELAYING_SYNACK(svp))) {#endif /* TCP_TRANSACTION_TCP */            tcp_no_more_data_in(svp);#ifdef TCP_TRANSACTION_TCP 			}#endif /* TCP_TRANSACTION_TCP */            sop = sv_valid_sop(svp, sop);            if (sop)            {#ifdef TCP_KEEP_ALIVE                if (so_keepalive(sop)) {                    /* don't need Keep-Alive anymore */                    tcp_end_ka(svp);                }#endif            so_notify(sop, WSHUTDOWN_NOTIFY);            }        }        break;      case FIN1_WAIT:		if (FIN_ON(flags)) {            svp->sv_flags |= SV_RFINFLG;    /* set FIN */		}        if ((svp->sv_flags & SV_SFINFLG) && ACK_ON(flags) && UC32M(ackno, ==, svp->sv_snxt))            /* FIN ACKed */            if (FIN_ON(flags)) {                /* 'tcp_stw' changes state to TIME_WAIT */                tcp_stw(svp, (u8)mp->m_ttl);                break;  /* switch */            } else                set_state("tcp_nstate", svp, FIN2_WAIT);        else if (FIN_ON(flags))            set_state("tcp_nstate", svp, CLOSING);        break;      case FIN2_WAIT:        if (FIN_ON(flags)) {            svp->sv_flags |= SV_RFINFLG;#ifdef KEEP_ON_CLOSE            tcp_stw(svp, (u8)mp->m_ttl);    /* 'tcp_stw' changes state to TIME_WAIT */#else            tcp_stw(svp, (u8)0);    /* 'tcp_stw' changes state to TIME_WAIT */#endif        }        break;    }    /* If no data was moved into the socket buffer from this packet, no reason to	   look at the holding queue */    if ( length == 0  ||  ((sop = sv_valid_sop(svp, sop)) == (so_t *)0) )        return (st)mp->m_dispfn;	/* See if in light of the data we've just put into the receive queue, we can	   now process a message in the hold queue. After scanning the hold queue, if	   we did not find any new in-order data and the queue is non-empty (i.e., 	   we still have out-of-order data), we should send an immediate ACK. */    {	 int still_have_out_of_order_data = false;	 int something_new_accepted;     something_new_accepted = tcp_process_hold_queue(mp);	 still_have_out_of_order_data = (!(is_header(&(((m *) sop->so_hq.gq_q.q_next)->m_q))));	 	 /* We have just processed an in-order segment. If it fills part of a gap	    left by some previously received out-of-order segments, and this segment didn't		close the gap (i.e., we haven't received the segment immediately following		the one we just processed), send an immediate ACK (canceling any delayed		ack that may presently be scheduled) to facilitate the peer's fast retransmit/		fast recovery */	 if ( still_have_out_of_order_data && !something_new_accepted ) {        tcp_sndack(mp, svp);	 } /* if */	}    /* We're completely finished with the incoming message */	return (st)mp->m_dispfn;}/***************************************************************************//*    This function looks thru the hold queue for the state vector         *//* associated with the passed-in message for a segment containing the      *//* next-expected sequence number. If it finds one, it removes that message *//* from the hold queue and puts it on the work queue of the passed-in      *//* message to be processed by "tcp_naccept".                               *//*    The function returns a 1 if a contiguous message was found and enqued*//* for processing by "tcp_naccept". It returns a zero otherwise.           *//*    As a side effect, if any segments are found in the hold queue whose  *//* entire sequence number range duplicates data that has already been      *//* received, those segments are put on the work queue of the passed-in     *//* message to be disposed of.                                              *//*  ASSUMPTIONS:                                                           *//*    -- the message is bound to a vaild state vector                      *//*    -- the state vector is bound to a valid socket                       *//*    -- this function is invoked from within a critical section           *//***************************************************************************/pflocal int tcp_process_hold_queue(m *mp){ tcpsv_t *svp = mp->m_svp; so_t    *sop; m *nmp, *nnmp; u32 seqno;  sop = sv_valid_sop(svp, sop); for (nmp = (m *)sop->so_hq.gq_q.q_next; !is_header(&nmp->m_q); nmp = nnmp) {     /* Don't wan

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -