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

📄 tcpsend.c

📁 用于嵌入式系统的TCP/IP协议栈
💻 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 + -