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

📄 tcpomach.c

📁 用于嵌入式系统的TCP/IP协议栈
💻 C
字号:
/***********************************************************************//*                                                                     *//*   Module:  tcp_ip/tcp/tcpomach.c                                    *//*   Release: 2001.3                                                   *//*   Version: 2001.0                                                   *//*   Purpose: TCP Output State Machine Implementation                  *//*                                                                     *//*---------------------------------------------------------------------*//*                                                                     *//*               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 <string.h>#include "../tcp_ipp.h"#include "tcp.h"/***********************************************************************//* Symbol Definitions                                                  *//***********************************************************************/#define R2_RETRIES      12      /* time to drop connection */#define R1_RETRIES      3       /* time to advise IP *//***********************************************************************//* Local Function Definitions                                          *//***********************************************************************//***********************************************************************//* sched_persist: Schedule persist window probes                       *//*                                                                     *//*       Input: sock = pointer to socket control block                 *//*                                                                     *//***********************************************************************/static void sched_persist(SOCKET sock){  int timeout = sock->persist_timeo;  /*-------------------------------------------------------------------*/  /* Limit and exponentially increase timeout if it is not too large.  */  /*-------------------------------------------------------------------*/  if (timeout >= MAX_PRS)    timeout = MAX_PRS;  else  {    if (timeout < MIN_PRS)      timeout = MIN_PRS;    sock->persist_timeo <<= 1;  }  /*-------------------------------------------------------------------*/  /* Schedule next window probe.                                       */  /*-------------------------------------------------------------------*/  NetTimerStart(&sock->out_tmr, timeout);}/***********************************************************************//* Global Function Definitions                                         *//***********************************************************************//***********************************************************************//*      TcpOut: Handle messages to TCP output state machine            *//*                                                                     *//*       Input: object = pointer to socket control block               *//*                                                                     *//*        Note: Must increment reserve_cnt before calling TcpOut()     *//*                                                                     *//***********************************************************************/void TcpOut(void *object){  int inflight, unsent;  SOCKET sock = object;  /*-------------------------------------------------------------------*/  /* Count inflight data and unsent data.                              */  /*-------------------------------------------------------------------*/  inflight = sock->snd_nxt - sock->snt_una;  unsent = sock->sb_count - inflight;  /*-------------------------------------------------------------------*/  /* SYN and FIN also count, one each.                                 */  /*-------------------------------------------------------------------*/  if (sock->flags & TCPF_SYN)    ++unsent;  if (sock->flags & SF_SNDFIN)    ++unsent;  /*-------------------------------------------------------------------*/  /* Check if there is no unsent data.                                 */  /*-------------------------------------------------------------------*/  if (unsent == 0)  {    /*-----------------------------------------------------------------*/    /* Check if everything sent has been acknowledged.                 */    /*-----------------------------------------------------------------*/    if (inflight == 0)    {      /*---------------------------------------------------------------*/      /* If not "idle", set "idle" and start congestion window timer.  */      /*---------------------------------------------------------------*/      if (sock->out_state != TCPO_IDLE)      {        sock->out_state = TCPO_IDLE;        NetTimerStart(&sock->out_tmr, sock->retrans_timeo);      }    }  }  /*-------------------------------------------------------------------*/  /* Else check if state is "idle" or "transmitting".                  */  /*-------------------------------------------------------------------*/  else if (sock->out_state <= TCPO_XMIT)  {    int window, room;    /*-----------------------------------------------------------------*/    /* If "idle", stop "idle" timer and change to "transmit".          */    /*-----------------------------------------------------------------*/    if (sock->out_state == TCPO_IDLE)    {      sock->out_state = TCPO_XMIT;      sock->flags &= ~SF_TIMING_RTT;      sock->retrans_count = 0;      NetTimerStop(&sock->out_tmr);    }    /*-----------------------------------------------------------------*/    /* Clip window to minimum of send window and congestion window.    */    /*-----------------------------------------------------------------*/    window = min(sock->snd_window, sock->snd_cwnd);    room = window - inflight;    /*-----------------------------------------------------------------*/    /* Loop while full-size segments can be sent or unsent data fits   */    /* in remaining room and either (1) Nagle algorithm is disabled,   */    /* (2) segment will be sent anyway, (3) no new transmit data is    */    /* coming, or (4) nothing is inflight.                             */    /*-----------------------------------------------------------------*/    while ((min(unsent, room) >= sock->snd_mss) || ((unsent <= room) &&      ((sock->flags & (SF_NODELAY | SF_SENDFLG | SF_SNDFIN)) ||        (inflight == 0))))    {      /*---------------------------------------------------------------*/      /* Send segment, break if no transmit buffer or route available. */      /*---------------------------------------------------------------*/      if (TcpSendSeg(sock, room))        break;      /*---------------------------------------------------------------*/      /* Recalculate amount inflight and unsent. Break if all sent.    */      /*---------------------------------------------------------------*/      inflight = sock->snd_nxt - sock->snt_una;      room = window - inflight;      unsent = sock->sb_count - inflight;      if (unsent <= 0)        break;    }    /*-----------------------------------------------------------------*/    /* Check if nothing in flight and unsent data remains.             */    /*-----------------------------------------------------------------*/    if ((inflight == 0) && unsent)    {      /*---------------------------------------------------------------*/      /* Change state to persist and and schedule first probe.         */      /*---------------------------------------------------------------*/      sock->out_state = TCPO_PERSIST;      sock->persist_timeo = sock->retrans_timeo;      sched_persist(sock);    }  }  /*-------------------------------------------------------------------*/  /* Send segment with no data if necessary flags have not been sent.  */  /*-------------------------------------------------------------------*/  if (sock->flags & SF_SENDFLG)    TcpSendSeg(sock, 0);  /*-------------------------------------------------------------------*/  /* If transmitting, ensure retransmit timer is running.              */  /*-------------------------------------------------------------------*/  if ((sock->out_state == TCPO_XMIT) && (sock->out_tmr.running == FALSE))    NetTimerStart(&sock->out_tmr, sock->retrans_timeo);  /*-------------------------------------------------------------------*/  /* Release hold on socket.                                           */  /*-------------------------------------------------------------------*/  SockRelease(sock);}/***********************************************************************//* TcpOutTimeout: Process TCP output timeouts                          *//*                                                                     *//*       Input: object = pointer to socket control block               *//*                                                                     *//***********************************************************************/void TcpOutTimeout(void *object){  SOCKET sock = object;  /*-------------------------------------------------------------------*/  /* After a retransmission timeout, enforce slow start.               */  /*-------------------------------------------------------------------*/  sock->snd_cwnd = sock->snd_mss;  /*-------------------------------------------------------------------*/  /* Finished if output state is idle.                                 */  /*-------------------------------------------------------------------*/  if (sock->out_state == TCPO_IDLE)    return;  /*-------------------------------------------------------------------*/  /* Check if more than R1_RETRIES have already been sent.             */  /*-------------------------------------------------------------------*/  if (++sock->retrans_count > R1_RETRIES)  {    /*-----------------------------------------------------------------*/    /* Clear cached route.                                             */    /*-----------------------------------------------------------------*/    sock->route = NULL;    /*-----------------------------------------------------------------*/    /* Forcefully drop connection after R2 retries if not waiting for  */    /* first acknowledgment (in which case connect() timeout applies). */    /*-----------------------------------------------------------------*/    if ((sock->retrans_count > R2_RETRIES) &&        ((sock->flags & TCPF_SYN) == 0))    {      sock->flags |= TCPF_RST;      TcpSendSeg(sock, 0);      TcpDrop(sock, sock->soft_error ? sock->soft_error : ECONNABORTED);      return;    }  }  /*-------------------------------------------------------------------*/  /* Process timeout according to output state.                        */  /*-------------------------------------------------------------------*/  switch (sock->out_state)  {    case TCPO_PERSIST:    {      int length = max(1, sock->snd_window);      /*---------------------------------------------------------------*/      /* Send persist window probe and schedule next probe.            */      /*---------------------------------------------------------------*/      sock->snd_nxt = sock->snt_una;      TcpSendSeg(sock, length);      sched_persist(sock);      break;    }    case TCPO_XMIT:      /*---------------------------------------------------------------*/      /* Change state to retransmit.                                   */      /*---------------------------------------------------------------*/      sock->out_state = TCPO_REXMT;      /*---------------------------------------------------------------*/      /* Double timeout if first acknowledgment has not been received. */      /*---------------------------------------------------------------*/      if (sock->flags & TCPF_SYN)        sock->retrans_timeo <<= 1;      /*---------------------------------------------------------------*/      /* Initialize slow start threshold to amount of inflight data.   */      /*---------------------------------------------------------------*/      sock->ssthresh = sock->snd_nxt - sock->snt_una;      /*---------------------------------------------------------------*/      /* Fall through to perform first retransmission.                 */      /*---------------------------------------------------------------*/      /*lint -fallthrough */    case TCPO_REXMT:    {      int timeout;      /*---------------------------------------------------------------*/      /* Set slow start threshold to max(half previous size, 2 MSS).   */      /*---------------------------------------------------------------*/      sock->ssthresh = max(sock->ssthresh >> 1, sock->snd_mss << 1);      /*---------------------------------------------------------------*/      /* Retransmit oldest unacknowledged segment.                     */      /*---------------------------------------------------------------*/      sock->snd_nxt = sock->snt_una;      TcpSendSeg(sock, sock->snd_mss);      ++Stats.TcpRetransSegs;      /*---------------------------------------------------------------*/      /* Schedule next retransmission using Karn's algorithm.          */      /*---------------------------------------------------------------*/      timeout = sock->retrans_timeo << 1;      sock->retrans_timeo = min(timeout, MAX_RXT);      NetTimerStart(&sock->out_tmr, sock->retrans_timeo);      break;    }  }}

⌨️ 快捷键说明

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