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

📄 tcp_fsm.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:

  tcp_ProcessData (s, tcp, len, flags);

  if (s->missed_seg[0])  /* must retransmit to get all data */
     return (1);

  if (flags & tcp_FlagFIN)
     s->locflags |= LF_GOT_FIN;

  if ((flags & flag_SYNACK) == flag_SYNACK &&
      ack == s->seqnum && seq == s->acknum)
  {
    s->acknum++;
    s->flags   = tcp_FlagACK;
    s->unhappy = FALSE;          /* don't send anything */
    s->state   = tcp_StateTIMEWT;
    s->timeout = set_timeout (tcp_TIMEWT_TO);
    TCP_SEND (s);
    return (0);
  }
  return (1);
}


/*
 * CLOSING state
 */
static int tcp_closing_state (tcp_Socket **sp, const in_Header *ip,
                              tcp_Header *tcp, int flags)
{
  tcp_Socket *s = *sp;

  if ((flags & flag_SYNACK) == tcp_FlagACK)  /* ACK, no FIN */
  {
    /* Per FINWT1 above, tcp->acknum should be s->seqnum+1,
     * which should cause us to bump s->seqnum to match
     */
// !! if ((tcp->acknum >= intel(s->seqnum) + 1) &&
      if (((long)(intel(tcp->acknum) - s->seqnum) > 0) && /* AGW - moved intel() so +1 OK 6th Jan 2001 */
          (tcp->seqnum == intel(s->acknum)))
      {
        s->seqnum++;
        s->state   = tcp_StateTIMEWT;
        s->unhappy = FALSE;
        s->timeout = set_timeout (tcp_TIMEWT_TO);
      }
  }
  ARGSUSED (ip);
  return (1);
}

/*
 * LASTACK state
 */
static int tcp_lastack_state (tcp_Socket **sp, const in_Header *ip,
                              tcp_Header *tcp, int flags)
{
  tcp_Socket *s = *sp;

  if (flags & tcp_FlagFIN)
  {
    /* they lost our two packets, back up
     */
    s->locflags |= LF_GOT_FIN;
    s->flags     = flag_SYNACK;
    TCP_SEND (s);
    s->unhappy = TRUE;
    return (0);
  }

//!! if ((intel(tcp->acknum) == (s->seqnum + 1)) &&
  if (((long)(intel(tcp->acknum) - s->seqnum) > 0) && /* AGW allow for any later acks 6th Jan 2001 */

      (intel(tcp->seqnum) == s->acknum))
  {
    s->state   = tcp_StateCLOSED;   /* no 2msl necessary */
    s->unhappy = FALSE;             /* we're done        */
    return (0);
  }
  ARGSUSED (ip);
  return (1);
}

/*
 * TIMEWAIT state
 */
static int tcp_timewt_state (tcp_Socket **sp, const in_Header *ip,
                             tcp_Header *tcp, int flags)
{
  tcp_Socket *s = *sp;

  if ((flags & flag_SYNACK) == flag_SYNACK)
  {
    /* our peer needs an ack
     */
    s->flags   = tcp_FlagACK;
    s->unhappy = FALSE;
    s->state   = tcp_StateCLOSED;  /* support 2 msl in RST code */
    TCP_SEND (s);
  }
  ARGSUSED (ip);
  ARGSUSED (tcp);
  return (1);
}


/*
 * Process the data in an incoming packet.
 * Called from all states where incoming data can be received:
 * SYNSENT, ESTAB, ESTCL, CLOSWT, FIN-WAIT-1 and FIN-WAIT-2
 */
static void tcp_ProcessData (tcp_Socket *s, tcp_Header *tcp, int len, int flags)
{
  long  ldiff, tmpldiff;
  int   diff,  tmpdiff, data_ofs;
  BYTE *data;

  if (s->stress > 0)
      s->stress--;

  s->window = intel16 (tcp->window);
  if (s->window > MAX_WINDOW)
      s->window = MAX_WINDOW;

  ldiff = s->acknum - intel (tcp->seqnum);

  if (flags & tcp_FlagSYN)
     ldiff--;                         /* back up to 0 */

  diff = abs ((int)ldiff);

  /* find the data portion
   */
  data_ofs = tcp->offset << 2;        /* dword to byte offset */
  data     = (BYTE*) tcp + data_ofs;

  if (data_ofs - sizeof(*tcp) > 0)    /* process TCP options */
  {
    BYTE *opt = (BYTE*)(tcp+1);

    while (opt < data)
    {
      switch (*opt)
      {
        case TCPOPT_EOL:
             opt = data;
             break;

        case TCPOPT_NOP:
             opt++;
             break;

        case TCPOPT_MAXSEG:   /* we are very liberal on MSS stuff */
             if (flags & tcp_FlagSYN)
             {
               WORD max_seg = intel16 (*(WORD*)(opt+2));
               if (max_seg < s->max_seg)
                   s->max_seg = max_seg;
             }
             opt += 4;
             break;

        case TCPOPT_TIMESTAMP:
             if ((flags & tcp_FlagSYN) ||
                 ((flags & tcp_FlagACK) && ldiff >= 0)) /* only if SEQ-num ACKs new data */
             {
               s->ts_recent = intel (*(DWORD*)(opt+2));
               s->ts_echo   = intel (*(DWORD*)(opt+6));
               s->locflags |= LF_RCVD_TSTMP;
             }
             opt += 10;
             break;

        case TCPOPT_WINDOW:
             if (flags & tcp_FlagSYN)
             {
               s->recv_wscale = min (TCP_MAX_WINSHIFT, *(opt+2));
               s->locflags |= LF_RCVD_SCALE;
             }
             opt += 4;
             break;
#if 0
        case TCPOPT_SACK_OK:
             if (flags & tcp_FlagSYN)
                s->locflags |= LF_SACK_PERMIT;
             opt += 2;
             break;
#endif

        default:              /* unknown options; type,length,... */
             opt += *(opt+1);
      }
    }
  }


  len -= data_ofs;     /* remove the header length */

#if 0  /* !!to-do */
  /*
   * Handle Out-of-Order data. Raise SIGURG.
   */
  if ((flags & tcp_FlagURG) &&
      tcp->urgent && intel16(tcp->urgent) < len)
  {
    intel16 (tcp->urgent) + intel16 (tcp->seqnum);
    STAT (tcpstats.tcps_rcvoopack++);
    STAT (tcpstats.tcps_rcvoobyte += len);
  }
#endif

  /*
   * SYN/RST segments shouldn't carry any data.
   */
  if ((flags & tcp_FlagSYN) == tcp_FlagSYN ||
      (flags & tcp_FlagRST) == tcp_FlagRST)
     return;


  /* Handle any new data that increments the ACK number
   */
  if (ldiff >= 0)
  {
    data += diff;
    len  -= diff;

    if (s->protoHandler)
        s->acknum += (*s->protoHandler) (s, data, len, NULL, NULL);
    else
    {
      /* no handler, just dump to buffer, should be indexed,
       * handles goofs limit receive size to our window
       */
      if (s->rdatalen >= 0)
      {
        int room = s->maxrdatalen - s->rdatalen;
        if (len > room)
            len = room;

        if (s->missed_seg[0])   /* don't write into missed segment */
        {
          tmpldiff = s->missed_seg[0] - s->acknum;
          tmpdiff  = abs ((int)tmpldiff);
          if (tmpldiff >= 0 && len > tmpdiff)
             len = tmpdiff;
        }
        if (len > 0)
        {
          s->acknum += len;   /* our new ack begins at end of data */
          memcpy (s->rdata + s->rdatalen, data, len);
          s->rdatalen += len;
        }

        if (s->missed_seg[0] && s->missed_seg[0] == s->acknum)
        {
          tmpldiff = s->missed_seg[1] - s->acknum;
          tmpdiff  = abs ((int)tmpldiff);
          if (tmpldiff > 0)
          {
            s->rdatalen += tmpdiff;
            s->acknum = s->missed_seg[1];
          }
          s->missed_seg[0] = 0L;
          s->missed_seg[1] = 0L;
        }
      }
    }

    s->unhappy = s->datalen ? TRUE : FALSE;

    if (ldiff == 0 && s->unacked && chk_timeout(s->rtt_lasttran))
    {
#if defined(USE_DEBUG)
      if (debug_on > 1)
         (*_printf)("data process timeout so set unacked "
                    "back to 0 from %u\r\n", s->unacked);
#endif
      s->unacked = 0;
      STAT (tcpstats.tcps_persistdrop++);  /* !! a better counter? */
    }
  }
  else    /* handle one out-of-segment packet */
  {
    DWORD seqnum = intel (tcp->seqnum);

#if 0
    /* S. Lawson - no out-of-sequence processing of FIN flag
     */
    *flags &= ~tcp_FlagFIN;
#endif

    if (s->missed_seg[0] == 0L)  /* just dropped a segment */
    {                         
      len = min (s->maxrdatalen - s->rdatalen - diff, len);
      if (len > 0)
      {
        memcpy (s->rdata + s->rdatalen + diff, data, len);
        s->missed_seg[0]  = s->missed_seg[1] = seqnum;
        s->missed_seg[1] += len;
      }
    }
    else  /* haven't seen missing segment yet */
    {     
      tmpldiff = s->missed_seg[0] - seqnum;
      tmpdiff  = abs ((int)tmpldiff);

      if (tmpldiff > 0 && len >= tmpdiff)  /* prepend bytes to fragment */
      {   
        memcpy (s->rdata + s->rdatalen + diff, data, tmpdiff);
        s->missed_seg[0] -= tmpdiff;
      }
      tmpldiff = seqnum + len - s->missed_seg[1];
      tmpdiff  = abs ((int)tmpldiff);

      /* append bytes touching fragment
       */
      if (tmpldiff > 0)
      {          
        tmpldiff = s->missed_seg[1] - seqnum;
        if (tmpldiff >= 0)
        {
          /* packet source offset
           */
          int dst, src = abs ((int)tmpldiff);
          tmpldiff = s->missed_seg[1] - s->acknum;

          /* buffer destination offset
           */
          dst = abs ((int)tmpldiff);

          /* length to move
           */
          tmpdiff = min (s->maxrdatalen - s->rdatalen - dst, tmpdiff);
          if (tmpdiff > 0)
          {
            memcpy (s->rdata + s->rdatalen + dst, data + src, tmpdiff);
            s->missed_seg[1] += tmpdiff;
          }
        }
      }
    }
  }
}


/*
 * Process the ACK value in received packet, but only if it falls within
 * current window. Discard queued data that have been acknowledged.
 */
static int tcp_ProcessAck (tcp_Socket *s, tcp_Header *tcp, long *unacked)
{
  long ldiff = (long) (intel(tcp->acknum) - s->seqnum);
  int  diff  = (int) ldiff;

  if (unacked)
     *unacked = ldiff;

  if (ldiff >= 0 && diff <= s->datalen)
  {
    if (s->queuelen)
    {
      s->queue    += diff;
      s->queuelen -= diff;
    }
    else if (diff < s->datalen)
      movmem (s->data+diff, s->data, s->datalen-diff);

    s->datalen -= diff;
    s->unacked -= diff;
    s->seqnum  += ldiff;
    return (1);
  }
  return (0);
}


/*
 * Format and send a reset tcp packet
 */
int _tcp_reset (tcp_Socket *s, const in_Header *his_ip, tcp_Header *old_tcp,
                const char *file, unsigned line)
{
  #include <sys/packon.h>
  struct packet {
         in_Header  ip;
         tcp_Header tcp;
         WORD       options[2];
       } *pkt;
  #include <sys/packoff.h>

  static DWORD next_RST_time = 0UL;

  tcp_PseudoHeader ph;
  BYTE         oldflags;
  in_Header   *ip;
  tcp_Header  *tcp;
  int          temp;

  /* see RFC 793 page 65 for details
   */
  if (next_RST_time && !chk_timeout(next_RST_time))
     return (-1);

  next_RST_time = set_timeout (tcp_RST_TIME);

  oldflags = old_tcp->flags;
  if (oldflags & tcp_FlagRST)
     return (-1);

  if (oldflags & tcp_FlagACK)                        /* ACK */
  {
    old_tcp->seqnum = old_tcp->acknum;
    old_tcp->acknum = 0;
    oldflags        = tcp_FlagRST;
  }
  else if ((oldflags & flag_SYNACK) == tcp_FlagSYN)  /* SYN, no ACK */
  {
    old_tcp->acknum = intel (intel(old_tcp->seqnum) + 1);
    old_tcp->seqnum = 0;
    oldflags        = tcp_FlagACK | tcp_FlagRST;
  }
  else
  {
    temp = intel16 (his_ip->length) - in_GetHdrLen (his_ip);
    old_tcp->acknum = intel (intel(old_tcp->seqnum) + temp);
    old_tcp->seqnum = 0;
    oldflags        = tcp_FlagRST;
  }

  if (s && (s->locflags & LF_NOPUSH))
     oldflags &= ~tcp_FlagPUSH;

  pkt = (struct packet*) _eth_formatpacket (MAC_SRC(his_ip), IP_TYPE);
  ip  = &pkt->ip;
  tcp = &pkt->tcp;

  /* tcp header
   */
  tcp->srcPort  = old_tcp->dstPort;
  tcp->dstPort  = old_tcp->srcPort;
  tcp->seqnum   = old_tcp->seqnum;
  tcp->acknum   = old_tcp->acknum;
  tcp->window   = 0;
  tcp->flags    = (oldflags | tcp_FlagRST);
  tcp->unused   = 0;
  tcp->offset   = sizeof(*tcp) / 4;
  tcp->checksum = 0;
  tcp->urgent   = 0;

  memset (&ph, 0, sizeof(ph));
  ph.src      = his_ip->destination;   /* already network order */
  ph.dst      = his_ip->source;
  ph.protocol = TCP_PROTO;
  ph.length   = intel16 (sizeof(*tcp));
  ph.checksum = checksum (tcp, sizeof(*tcp));

  tcp->checksum = ~checksum (&ph, sizeof(ph));

  return _ip_output (ip, ph.src, ph.dst, TCP_PROTO,
                     s ? s->ttl : _default_ttl,
                     his_ip->tos, 0, sizeof(*tcp), s, file, line);
}

#endif /* !USE_UDP_ONLY */

⌨️ 快捷键说明

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