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

📄 tcpsend.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 4 页
字号:
/*     -- how is the socket configured vis-a-vis socket options             *//*     -- Whether this is a SYN segment or a data segment                   *//* Size of options is the return function value, and also returns the       */ /* options this size is based on in which_options */export int tcp_seg_optsize(fast tcpsv_t *svp, int synseg, u16 *which_options){ int optsize = 0; /* Find out which options we should send, based on the configuration of this    socket and/or what options we received in an incoming SYN */ *which_options = tcp_seg_which_options(svp,synseg);  /* See if MSS option is needed. */ if (*which_options & TCP_OPT_INCLUDE_MSS) optsize += TCPO_MSS_LEN;#ifdef TCP_TIMESTAMPS /* See if the timestamps option is needed. If so, we want to align it    so that the timestamp fields are aligned on 4-byte-multiple offsets    from the beginning of the options, as recommended in Appendix A    of RFC 1323. So, add enough to our accumulating size to account for    that alignment */ if (*which_options & TCP_OPT_INCLUDE_TIMESTAMPS) {	 int op2mod4 = ( (optsize + 2) % 4);	 if (op2mod4) optsize += ( 4 - op2mod4);	 	 optsize += TCPO_TMSTMP_LEN; } /* if */#endif /* TCP_TIMESTAMPS */#ifdef TCP_WND_SCALE /* See if Window scale option is needed. */ if (*which_options & TCP_OPT_INCLUDE_WSF) optsize += TCPO_WSF_LEN;#endif /* TCP_WND_SCALE */#ifdef TCP_SELACK_ENHANCEMENTS     /* See if the SACK_PERMITTED option is needed */ if (*which_options & TCP_OPT_INCLUDE_SACK_PERMITTED) optsize += TCPO_SACK_PERMITTED_LEN;#endif#ifdef TCP_TRANSACTION_TCP if (*which_options & TCP_OPT_INCLUDE_CC) optsize += TCPO_CC_LEN; if (*which_options & TCP_OPT_INCLUDE_CCNEW) optsize += TCPO_CCNEW_LEN; if (*which_options & TCP_OPT_INCLUDE_CCECHO) optsize += TCPO_CCECHO_LEN;#endif /* TCP_TRANSACTION_TCP */ /* If the accumulated length is not a multiple of 4, round it up to such a    multiple. */ if ( (optsize % 4) != 0 )    optsize += (4 - (optsize % 4) ); return(optsize);} /* tcp_seg_optsize *//**************************************************************************//* Function to construct the options field of a TCP segment, given the    *//* set of options passed in the parameter which_options. The options are  *//* to be constructed in the buffer pointed to by optr, of length olen.    *//* The buffer is to be padded with NOPS if it is longer than needed to    *//* contain the specified options. If it is not long enough, we have a bug.*/export void tcp_construct_seg_options(fast tcpsv_t *svp, char *optr, int olen, 									  u16 which_options){ fast TCPO_T *options = (TCPO_T *) optr; /* IMPORTANT: THE ORDER IN WHICH OPTIONS ARE CONSTRUCTED HERE MUST BE THE    SAME AS THAT WHICH THEY WERE CONSIDERED IN "tcp_seg_optsize", AND ALL	LOGIC CONCERNING ALIGNMENT AND PADDING MUST BE IDENTICAL HERE TO THAT	WHICH WAS USED THERE. */ if (which_options & TCP_OPT_INCLUDE_MSS) {    assert( ((u32)(options + TCPO_MSS_LEN) <= (u32)(optr + olen) ), "tcp mss option overflow");	options[TCPO_KIND] = TCPO_MSS_KIND;    options[TCPO_SIZE] = TCPO_MSS_LEN;    /* the value of this option will be 'dink'ed later */    options += TCPO_MSS_LEN; } /* if */#ifdef TCP_TIMESTAMPS /* Pad with NOPs if necessary to achieve the preferred alignment. See comment in    "tcp_seg_optsize" about that alignment */ if (which_options & TCP_OPT_INCLUDE_TIMESTAMPS) {	while ( ((((char *) options) - optr) % 4) != 2) {		*options++ = TCPO_NOP_KIND;	} /* while */ 	assert( ((u32)(options + TCPO_TMSTMP_LEN) <= (u32)(optr + olen) ), "tcp timestamp option overflow");	options[TCPO_KIND] = TCPO_TMSTMP_KIND;    options[TCPO_SIZE] = TCPO_TMSTMP_LEN;    HostToNet32(&(options[TCPO_TMSTMP_TSVAL]),TCP_CURRENT_HRES_TIME );    /* Per RFC 1323, the following fields must be zero if the ACK bit in the outgoing	   segment is not set. I'll need to come back and deal with that later */    HostToNet32(&(options[TCPO_TMSTMP_TSECR]),svp->sv_recent_rx_tmstmp);    options += TCPO_TMSTMP_LEN; }#endif /* TCP_TIMESTAMPS */#ifdef TCP_WND_SCALE if (which_options & TCP_OPT_INCLUDE_WSF) {    assert( ((u32)(options + TCPO_WSF_LEN) <= (u32)(optr + olen) ), "tcp wsf option overflow");    options[TCPO_KIND] = TCPO_WSF_KIND;    options[TCPO_SIZE] = TCPO_WSF_LEN;	options[TCPO_VAL]  = (u8) tcp_rcv_wscale_value(svp);    options += TCPO_WSF_LEN; } /* if */#endif /* TCP_WND_SCALE */#ifdef TCP_SELACK_ENHANCEMENTS if (which_options & TCP_OPT_INCLUDE_SACK_PERMITTED) {    assert( ((options + TCPO_SACK_PERMITTED_LEN) <= (optr + olen) ), 		                                      "tcp sack permitted option overflow");    options[TCPO_KIND] = TCPO_SACK_PERMITTED_KIND;    options[TCPO_SIZE] = TCPO_SACK_PERMITTED_LEN;    options += TCPO_SACK_PERMITTED_LEN; }#endif /* TCP_SELACK_ENHANCEMENTS */#ifdef TCP_TRANSACTION_TCP if (which_options & TCP_OPT_INCLUDE_CC) {    assert( ((options + TCPO_CC_LEN) <= (optr + olen) ), "tcp CC option overflow");    options[TCPO_KIND] = TCPO_CC_KIND;    options[TCPO_SIZE] = TCPO_CC_LEN;    HostToNet32(&(options[TCPO_CC_VAL]),svp->sv_ccsend );    options += TCPO_CC_LEN; } if (which_options & TCP_OPT_INCLUDE_CCNEW) {     assert( ((options + TCPO_CCNEW_LEN) <= (optr + olen) ), "tcp CCNEW option overflow");    options[TCPO_KIND] = TCPO_CCNEW_KIND;    options[TCPO_SIZE] = TCPO_CCNEW_LEN;    HostToNet32(&(options[TCPO_CCNEW_VAL]),svp->sv_ccsend );    options += TCPO_CCNEW_LEN; } if (which_options & TCP_OPT_INCLUDE_CCECHO) {    assert( ((options + TCPO_CCECHO_LEN) <= (optr + olen) ), "tcp CCECHO option overflow");    options[TCPO_KIND] = TCPO_CCECHO_KIND;    options[TCPO_SIZE] = TCPO_CCECHO_LEN;    HostToNet32(&(options[TCPO_CCECHO_VAL]),svp->sv_ccrecv );    options += TCPO_CCECHO_LEN; }#endif /* TCP_TRANSACTION_TCP */#ifdef TCP_SELACK_ENHANCEMENTS if (which_options & TCP_OPT_INCLUDE_SACK) {	 int sack_block_count;	 int sbi;	 /* How many do we have room for? */	 sack_block_count = tcp_num_sack_blocks_room_for( (optr + olen) - ((char *) options) );	 /* Adjust count downward if we have fewer SACK blocks than that */     if (svp->sv_num_out_sack_blocks < sack_block_count) {	     sack_block_count = svp->sv_num_out_sack_blocks;	 } /* if */	 /* Put the option header in */     options[TCPO_KIND] = TCPO_SACK_KIND;     options[TCPO_SIZE] = ( TCPO_VAL + (TCPO_SACK_BLOCK_SIZE * sack_block_count) );     options += TCPO_VAL;	 /* Copy the number of SACK blocks into the header that we have decided we need or	    have room for. Start from the most-redently added SACK block */	 sbi = (MAX_NUM_OUT_SACK_BLOCKS - svp->sv_num_out_sack_blocks);     while (sack_block_count > 0 ) {	     tcp_sack_block_ *sbp = &(svp->sv_out_sack_blocks[sbi]);         /* The SACK blocks are stored in network order so no need for conversion here */		 *((u32 *) options) = sbp->begin_seqno;		 *((u32 *) (options + sizeof(u32) ) ) = sbp->end_seqno;		 options += TCPO_SACK_BLOCK_SIZE;		 sack_block_count--;		 sbi++;	 } /* while */ }#endif /* TCP_SELACK_ENHANCEMENTS */ /* If we are not on a 4-byte boundary, put in an end-of-list option */ if ( ( ( (char *) options - optr) % 4 ) != 0)	 options[TCPO_KIND] = TCPO_EOL_KIND;} /* tcp_construct_seg_options *//***************************************************************************//* Function to find a specified option within the options field of a TCP   *//* segment header. Returns a pointer to the specified option or NULL if its*//* not present.                                                            */export TCPO_T *tcp_find_option(TCPH_T *tcphp, u8 kind){ TCPO_T *opptr = (TCPO_T *) TCPHOPTPTR(tcphp);  TCPO_T *endopptr = (TCPO_T *) ( opptr + TCPHOPTL(tcphp) ); /* loop thru the options until we reach the end of the options */ while (opptr < endopptr) {	 /* Have we found the one we're looking for? */     if (*opptr == kind) return(opptr);	 /* Is this the end of the option list? */	 if (*opptr == TCPO_EOL_KIND) break;	 /* Bump to the next option */	 switch (*opptr) {        /* Options with only a "kind" field */	    case TCPO_NOP_KIND: 	        opptr++;break;        /* Option with a "kind" and a "length" field */        default:			opptr += opptr[TCPO_SIZE]; break;	 } /* switch */ } /* for */ /* If down here we did not find the speecified option type */ return((TCPO_T *) 0);} /* tcp_find_option *//***************************************************************************//* Send queue transmission * Retransmission policy only sends out the first unacknowledged packet */export  void     tcp_sqxmit (fast tcpsv_t *svp){    fast    m       * mp = (m *)0, * nmp;    fast    i32     i1, nsend;    fast    u32     seqno;    boolean         finflg, synflg;	boolean retransmitting;#ifdef FAST_REXMT_DEBUG	int entered_with_rip_flag_set = 0;	int iter_ctr = 0;#endif	boolean loop_again = true;    char            * dp = (char *)0;    so_t        * sop;#ifdef TRACE_SQXMIT  int local_inv_ctr;#endif	use_critical;    trace0(tcp_trace, "tcp_sqxmit:\n");    /* if another instance of this routine is running, we're done */    if (svp->sv_flags & SV_SENDING) {        return;	}    nmp = (m *)0;   /* for testing first-time through calculations */#ifdef TRACE_SQXMIT	critical;    inv_ctr++;	local_inv_ctr = inv_ctr;	normal;#endif    svp->sv_flags &= ~SV_UPSEND_PENDING;#ifdef FAST_REXMT_DEBUG	if (svp->sv_flags & SV_RIP) {	   os_printf("\n(%d) tcp_sqxmit: entering with RIP flag set, suna=%u\n",		           t_time, MU32(svp->sv_suna));	   entered_with_rip_flag_set = 1;	}#endiftop:;    critical;    sop = sv_valid_sop(svp,sop); /* validity of sop will be checked in various								    places below as necessary */#ifdef FAST_REXMT_DEBUG		if (entered_with_rip_flag_set) {			os_printf("\n(%d) (i=%d) at top, suna=%u\n", 				      t_time,++iter_ctr,MU32(svp->sv_suna));		}#endif    /* turn off sending condition; eases the many returns below */    svp->sv_flags &= ~SV_SENDING;    assert(svp->sv_refcnt != 0, "tcp_sqxmit: sv not bound\n");    if ( svp->sv_state == CLOSED || (sop == (so_t *)0) ) {		normal;        return;    } /* if */    assert(MC32M(svp->sv_suna, <=, svp->sv_surg), "tcp_sqxmit: surg too small\n");    assert(MC32M(svp->sv_surg, <=, svp->sv_snxt), "tcp_sqxmit: surg too big\n");    assert(MC32M(svp->sv_suna, <=, svp->sv_spsh), "tcp_sqxmit: spsh too small\n");    assert(MC32M(svp->sv_spsh, <=, svp->sv_snxt), "tcp_sqxmit: spsh too big\n");    trace3(tcp_tsqxmit, "tcp_sqxmit: suna 0x%x spsh 0x%x snxt 0x%x\n", MU32(svp->sv_suna), MU32(svp->sv_spsh), MU32(svp->sv_snxt));    /* Decide whether or not we want this interation to retransmit a segment or	   to send new data */#ifndef TCP_RETRANSMIT_ENHANCEMENTS	retransmitting = ( (svp->sv_flags & SV_RIP) != 0);#else	retransmitting = ( ((svp->sv_flags & SV_RIP) != 0) && (svp->sv_retr_window > 0) );#endif    /******************************************************/	/* Determine the sequence # of first byte to be sent, */	/* and the amount of data to send in this segment     */    /******************************************************/    if (retransmitting) { /* retransmission */        /* retransmit 1 segment from unacknowledged pointer */

⌨️ 快捷键说明

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