📄 tcpsend.c
字号:
/***********************************************************************//* *//* Module: tcp_ip/tcp/tcpsend.c *//* Release: 2001.3 *//* Version: 2001.0 *//* Purpose: TCP Output Routines *//* *//*---------------------------------------------------------------------*//* *//* Copyright 2001, Blunk Microsystems *//* ALL RIGHTS RESERVED *//* *//* Licensees have the non-exclusive right to use, modify, or extract *//* this computer program for software development at a single site. *//* This program may be resold or disseminated in executable format *//* only. The source code may not be redistributed or resold. *//* *//***********************************************************************/#include "../tcp_ipp.h"#include "tcp.h"#include "../ip/ip.h"/***********************************************************************//* Configuration *//***********************************************************************/#define CKSUM_TEST FALSE /* enables test of one-copy checksum */#define ONE_COPY_SND TRUE/***********************************************************************//* Function Prototypes *//***********************************************************************/static ui8 set_rmss_opt(CSOCKET sock, const NetBuf *buf);/***********************************************************************//* Global Function Definition *//***********************************************************************//***********************************************************************//* TcpSendSeg: Compute and send TCP segment for given socket *//* *//* Inputs: sock = pointer to TCP socket *//* window = maximum number of bytes allowed in segment *//* *//* Returns: 0 for success or -1 if no transmit buffer or route *//* *//***********************************************************************/int TcpSendSeg(SOCKET sock, int window){ Ip *ip; Tcp *tcp; int datalen, inflight; Route *route; NetBuf *buf;#if CKSUM_TEST NetBuf *tbuf; Tcp *ttcp; Ip *tip;#endif /*-------------------------------------------------------------------*/ /* Restrict window to maximum allowed segment size. */ /*-------------------------------------------------------------------*/ if (window > sock->snd_mss) window = sock->snd_mss; /*-------------------------------------------------------------------*/ /* Find route for this destination, using cached route if available. */ /*-------------------------------------------------------------------*/ if (sock->route) route = sock->route; else { route = RtSearch(sock->remote.sin_addr.s_addr); if (route == NULL) { ++Stats.IpOutNoRoutes; return -1; } sock->route = route; } /*-------------------------------------------------------------------*/ /* Determine amount of available data and amount in flight. */ /*-------------------------------------------------------------------*/ inflight = sock->snd_nxt - sock->snt_una; datalen = sock->sb_count - inflight; /*-------------------------------------------------------------------*/ /* Clip data length between zero and the specified window size. */ /*-------------------------------------------------------------------*/ if (datalen < 0) datalen = 0; else if (window < datalen) datalen = window; /*-------------------------------------------------------------------*/ /* Allocate a network buffer for the output. */ /*-------------------------------------------------------------------*/#if ONE_COPY_SND buf = tcpGetBuf(NIMHLEN + IPMHLEN + TCPMHLEN);#if CKSUM_TEST tbuf = tcpGetBuf(NIMHLEN + IPMHLEN + TCPMHLEN + datalen);#endif#else buf = tcpGetBuf(NIMHLEN + IPMHLEN + TCPMHLEN + datalen);#endif if (buf == NULL) return -1; /*-------------------------------------------------------------------*/ /* Clear "output needed" flag, we're doing it. */ /*-------------------------------------------------------------------*/ sock->flags &= ~SF_SENDFLG; /*-------------------------------------------------------------------*/ /* Start TCP header initialization. */ /*-------------------------------------------------------------------*/ tcp = buf->ip_data; tcp->src_port = sock->local.sin_port; tcp->dst_port = sock->remote.sin_port; tcp->ack_num = htonl(sock->rcv_nxt); tcp->window = TcpRcvWin(sock); /*-------------------------------------------------------------------*/ /* Begin flags initialization. May get SYN, ACK, and RST. */ /*-------------------------------------------------------------------*/ tcp->flags = (ui8)sock->flags; /*-------------------------------------------------------------------*/ /* Set MSS option and use initial sequence number iff sending SYN. */ /*-------------------------------------------------------------------*/ if (tcp->flags & TCPF_SYN) { tcp->seq_num = htonl(sock->snt_una); sock->snd_nxt = sock->snt_una + 1; tcp->offset = set_rmss_opt(sock, buf); } else { tcp->seq_num = htonl(sock->snd_nxt); tcp->offset = TCPHOFFSET; } /*-------------------------------------------------------------------*/ /* Set FIN if sequence number reached. */ /*-------------------------------------------------------------------*/ if ((sock->flags & SF_SNDFIN) && (sock->snd_nxt + datalen == sock->fin_seq)) { tcp->flags |= TCPF_FIN; ++sock->snd_nxt; } /*-------------------------------------------------------------------*/ /* Set segment's urgent data pointer (BSD interpretation). */ /*-------------------------------------------------------------------*/ if ((sock->flags & SF_SUPOK) && SEQ_GE(sock->surg_seq, sock->snd_nxt) && SEQ_LT(sock->surg_seq, sock->snd_nxt + 0xFFFF)) { int offset = sock->surg_seq - sock->snd_nxt + 1; tcp->urg_ptr = htons(offset); tcp->flags |= TCPF_URG; } else tcp->urg_ptr = 0;#if CKSUM_TEST /*-------------------------------------------------------------------*/ /* Assign pointer to test TCP header and copy real header to it. */ /*-------------------------------------------------------------------*/ ttcp = tbuf->ip_data; memcpy(ttcp, tcp, TCP_HLEN(tcp));#endif /*-------------------------------------------------------------------*/ /* Check if data is being sent. */ /*-------------------------------------------------------------------*/ if (datalen) { /*-----------------------------------------------------------------*/ /* Calculate index into send buffer and pointer to segment data. */ /*-----------------------------------------------------------------*/ int sboff = (sock->sb_start + inflight) % sock->sb_size;#if !ONE_COPY_SND char *pch = (char *)(buf->ip_data) + TCP_HLEN(tcp);#endif#if CKSUM_TEST char *tpch = (char *)(tbuf->ip_data) + TCP_HLEN(tcp);#endif /*-----------------------------------------------------------------*/ /* Always set push when sending data. */ /*-----------------------------------------------------------------*/ tcp->flags |= TCPF_PSH;#if CKSUM_TEST ttcp->flags |= TCPF_PSH;#endif /*-----------------------------------------------------------------*/ /* Copy data from send buffer to outgoing segment. */ /*-----------------------------------------------------------------*/ if ((sboff + datalen) <= sock->sb_size) {#if ONE_COPY_SND buf->order = 1; buf->app_data = &sock->sbuf[sboff]; buf->app_len = datalen;#if CKSUM_TEST memcpy(tpch, &sock->sbuf[sboff], datalen);#endif#else memcpy(pch, &sock->sbuf[sboff], datalen);#endif } else { int len1 = sock->sb_size - sboff; int len2 = datalen - len1;#if ONE_COPY_SND buf->order = 2; buf->app_data = &sock->sbuf[sboff]; buf->app_data2 = &sock->sbuf[0]; buf->app_len = len1; buf->app_len2 = len2;#if CKSUM_TEST memcpy(tpch, &sock->sbuf[sboff], len1); memcpy(tpch + len1, &sock->sbuf[0], len2);#endif#else memcpy(pch, &sock->sbuf[sboff], len1); memcpy(pch + len1, &sock->sbuf[0], len2);#endif } /*-----------------------------------------------------------------*/ /* Advance snd_nxt for amount of data being sent. */ /*-----------------------------------------------------------------*/ sock->snd_nxt += datalen; } /*-------------------------------------------------------------------*/ /* Update record of highest sequence number sent. */ /*-------------------------------------------------------------------*/ if (SEQ_GT(sock->snd_nxt, sock->max_snt)) { /*-----------------------------------------------------------------*/ /* Start round trip timing if not in progress. */ /*-----------------------------------------------------------------*/ if ((sock->flags & SF_TIMING_RTT) == FALSE) { sock->flags |= SF_TIMING_RTT; sock->rtt_seq = sock->max_snt; NetTimerStop(&sock->out_tmr); } sock->max_snt = sock->snd_nxt; } /*-------------------------------------------------------------------*/ /* Stop delayed acknowledgment timer. */ /*-------------------------------------------------------------------*/ NetTimerStop(&sock->ack_tmr); /*-------------------------------------------------------------------*/ /* If requested and connection established, reset keep-alive timer. */ /*-------------------------------------------------------------------*/ if ((sock->state == SS_ESTABLISHED) && (sock->flags & SF_KEEPALIVE)) NetTimerStart(&sock->state_tmr, KEEPALIVE_TIMEO); /*-------------------------------------------------------------------*/ /* Begin IP header initialization. */ /*-------------------------------------------------------------------*/ ip = (Ip *)buf->ip_pkt; ip->protocol = IPT_TCP; ip->src_ip = sock->local.sin_addr.s_addr; ip->dst_ip = sock->remote.sin_addr.s_addr;#if CKSUM_TEST /*-------------------------------------------------------------------*/ /* Assign pointer to test IP header and copy IP addresses to it. */ /*-------------------------------------------------------------------*/ tip = (Ip *)tbuf->ip_pkt; tip->src_ip = sock->local.sin_addr.s_addr; tip->dst_ip = sock->remote.sin_addr.s_addr;#endif /*-------------------------------------------------------------------*/ /* Calculate checksum. */ /*-------------------------------------------------------------------*/ buf->length = TCP_HLEN(tcp) + datalen; tcp->cksum = 0; tcp->cksum = TcpCheckSum(buf);#if CKSUM_TEST /*-------------------------------------------------------------------*/ /* Calculate test checksum and compare with real checksum. */ /*-------------------------------------------------------------------*/ tbuf->length = TCP_HLEN(tcp) + datalen; ttcp->cksum = 0; ttcp->cksum = TcpCheckSum(tbuf); if (tcp->cksum != ttcp->cksum) { printf("tcp->cksum = 0x%04X, ttcp->cksum = 0x%04X\n", tcp->cksum, ttcp->cksum); tbuf->length = buf->length = TCP_HLEN(tcp) + datalen; ttcp->cksum = tcp->cksum = 0; tcp->cksum = TcpCheckSum(buf); ttcp->cksum = TcpCheckSum(tbuf); TcpAssert(tcp->cksum == ttcp->cksum); } /*-------------------------------------------------------------------*/ /* Test is finished, so return test buffer. */ /*-------------------------------------------------------------------*/ tcpRetBuf(&tbuf);#endif /*-------------------------------------------------------------------*/ /* Pass to IP for delivery and track how many TCP segments are sent. */ /*-------------------------------------------------------------------*/ IpSend(route, buf, buf->length, sock->ip_tos); ++Stats.TcpOutSegs; return 0;}/***********************************************************************//* Local Function Definitions *//***********************************************************************//***********************************************************************//* set_rmss_opt: set receive MSS option *//* *//* Returns: updated TCP offset value *//* *//* Note: Assumes MSS is first option *//* *//***********************************************************************/static ui8 set_rmss_opt(CSOCKET sock, const NetBuf *buf){ Ip *ip = (Ip *)buf->ip_pkt; Tcp *tcp = buf->ip_data; /*-------------------------------------------------------------------*/ /* Lay out option kind code and length. */ /*-------------------------------------------------------------------*/ ip->options[TCPMHLEN] = TPO_MSS; /* option kind */ ip->options[TCPMHLEN + 1] = 4; /* option length */ /*-------------------------------------------------------------------*/ /* Lay MSS value out in network byte order. */ /*-------------------------------------------------------------------*/ ip->options[TCPMHLEN + 2] = (ui8)(sock->rcv_mss >> 8); ip->options[TCPMHLEN + 3] = (ui8)sock->rcv_mss; /*-------------------------------------------------------------------*/ /* Correct TCP data offset. Header length is in high nibble. */ /*-------------------------------------------------------------------*/ return (((TCPMHLEN + 4) << 2) & 0xF0) | (tcp->offset & 0xF);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -