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

📄 pctcp.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    if (len > 0)
    {
      if (buf)
         memcpy (buf, s->rdata, len);
      s->rdatalen -= len;
      if (s->rdatalen)
         movmem (s->rdata+len, s->rdata, s->rdatalen);
    }
  }
  return (len);
}

void _udp_cancel (const in_Header *ip, int type, const char *msg, DWORD gateway)
{
  WORD        srcPort, dstPort;
  int         len     = in_GetHdrLen (ip);
  BOOL        passive = FALSE;
  udp_Header *udp     = (udp_Header*) ((BYTE*)ip + len);
  udp_Socket *s;

  srcPort = intel16 (udp->srcPort);
  dstPort = intel16 (udp->dstPort);

  for (s = _udp_allsocs; s; s = s->next)  /* demux to active sockets */
  {
    if (s->hisport && dstPort == s->hisport && srcPort == s->myport &&
        intel(ip->destination) == s->hisaddr)
       break;
  }

  if (!s)       /* check passive sockets */
  {
    passive = TRUE;
    for (s = _udp_allsocs; s; s = s->next)
        if (s->hisport == 0 && dstPort == s->myport)
           break;
  }

  if (s)  
  {
    if (s->err_msg == NULL && msg)
        s->err_msg = msg;

    if (s->sol_callb)            /* tell the socket layer about it */
      (*s->sol_callb) ((void*)s, type);

    if (type == ICMP_REDIRECT && /* handle redirect on active sockets */
        !passive)
    {
      _ip_recursion = 1;
      _arp_resolve (gateway, &s->hisethaddr, 1);
      _ip_recursion = 0;
    }
    else if (type != ICMP_TIMXCEED)
    {
      s->rdatalen = 0;  /* will it be unthreaded ? */
      s->ip_type  = 0;
      s->err_msg  = _LANG("Port unreachable");
    }
  }
  else
  {
    /* tell the INADDR_ANY sockets about it
     */
    for (s = _udp_allsocs; s; s = s->next)
    {
      if (s->sol_callb)
        (*s->sol_callb) ((void*)s, type);
    }
  }
}

#if !defined(USE_UDP_ONLY)
void _tcp_cancel (const in_Header *ip, int type, const char *msg, DWORD gateway)
{
  tcp_Header *tcp = (tcp_Header*) ((BYTE*)ip + in_GetHdrLen (ip));
  tcp_Socket *s;

  WORD srcPort = intel16 (tcp->srcPort);
  WORD dstPort = intel16 (tcp->dstPort);

  /* demux to active sockets
   */
  for (s = _tcp_allsocs; s; s = s->next)
  {
    if (srcPort == s->myport && dstPort == s->hisport &&
        intel(ip->destination) == s->hisaddr)
    {
      switch (type)
      {
        case ICMP_TIMXCEED:
             if (s->ttl < 255)
                 s->ttl++;
             /* FALLTROUGH */

        case ICMP_UNREACH:
             if (s->stress++ > s->rigid && s->rigid < 100)  /* halt it */
             {
               s->err_msg  = msg ? msg : _LANG("ICMP closed connection");
               s->rdatalen = 0;
               s->datalen  = 0;
               s->unhappy  = FALSE;
               tcp_abort (s);
               break;
             }
             /* FALLTROUGH */

        case ICMP_SOURCEQUENCH:    
             s->cwindow = 1;       /* slow-down tx-rate */
             s->wwindow = 1;
             s->vj_sa <<= 2;
             s->vj_sd <<= 2;
             s->rto   <<= 2;
             tcp_rtt_add (s, s->rto);
             break;

        case ICMP_REDIRECT:
             /* don't bother handling redirect if we're closing
              */
             if (s->state >= tcp_StateFINWT1)
             {
               if (s->err_msg == NULL && msg)
                   s->err_msg = msg;
               break;
             }
             _ip_recursion = 1;
             _arp_resolve (gateway, &s->hisethaddr, 1);
             _ip_recursion = 0;
             break;

        case ICMP_PARAMPROB:
             tcp_abort (s);
             break;
      }
      if (s->sol_callb)
        (*s->sol_callb) ((void*)s, type);
    }
  }
}

/*
 * tcp_read - read socket data to 'buf', does large buffering
 */
static int tcp_read (tcp_Socket *s, BYTE *buf, int maxlen)
{
  int len = s->rdatalen;

  if (maxlen < 0)
      maxlen = INT_MAX;

  if (len > 0)
  {
    if (len > maxlen)
        len = maxlen;
    if (len > 0)
    {
      if (buf)
         memcpy (buf, s->rdata, len);
      s->rdatalen -= len;
      if (s->missed_seg[0] || s->rdatalen > 0)
      {
        int diff = 0;
        if (s->missed_seg[0] != 0)
        {
          long ldiff = s->missed_seg[1] - s->acknum;
          diff = abs ((int)ldiff);
        }
        movmem (s->rdata + len, s->rdata, s->rdatalen + diff);
        TCP_SENDSOON (s);     /* update the window soon */
      }
      else
        tcp_upd_wind (s, __LINE__);
    }
  }
  else if (s->state == tcp_StateCLOSWT)
          _tcp_close (s);
  return (len);
}

/*
 * Write data to a connection.
 * Returns number of bytes written, == 0 when no room in socket-buffer
 */
static int tcp_write (tcp_Socket *s, const BYTE *data, UINT len)
{
  UINT room;

  if (s->state != tcp_StateESTAB)
     return (0);

  room = tcp_MaxTxBufSize - s->datalen;
  if (len > room)
      len = room;
  if (len > 0)
  {
    int rc = 0;

    memcpy (s->data + s->datalen, data, len);
    s->datalen  += len;
    s->unhappy   = TRUE;    /* redundant because we have outstanding data */
    s->datatimer = set_timeout (1000 * sock_data_timeout); /* EE 99.08.23 */

    if (s->sockmode & TCP_LOCAL)    /* queue up data, flush on next write */
    {
      s->sockmode &= ~TCP_LOCAL;
      return (len);
    }

    if (s->sockmode & TCP_MODE_NONAGLE)
       rc = TCP_SEND (s);
    else
    {
      /* transmit if first data or reached MTU.
       * not true MTU, but better than nothing
       */
      if (s->datalen == len || s->datalen > s->max_seg/2)
           rc = TCP_SEND (s);
      else rc = TCP_SENDSOON (s);
    }
    if (rc < 0)
       return (-1);
  }        
  return (len);
}



/*
 *  Find the socket with the tripplet:
 *  DESTADDR=MYADDR,DESTPORT=MYPORT and ACKNUM=SEQNUM+1
 */
static tcp_Socket *tcp_findseq (const in_Header *ip, const tcp_Header *tcp)
{
  tcp_Socket *s;
  DWORD      dstHost = intel (ip->destination);
  DWORD      ackNum  = intel (tcp->acknum);
  WORD       dstPort = intel16 (tcp->dstPort);

  for (s = _tcp_allsocs; s; s = s->next)
  {     
    if (s->hisport != 0      &&
        dstHost == s->myaddr &&
        dstPort == s->myport &&
        ackNum  == (s->seqnum+1))
      break;
  }
  return (s);
}

static void tcp_sockreset (tcp_Socket *s, int proxy)
{
  char *str = proxy ? "Proxy reset connection"
                    : "Remote reset connection";
  if (debug_on)
     outsnl (_LANG(str));

  s->datalen = 0;  /* Flush Tx buffer */

  if (s->state != tcp_StateCLOSED && s->state != tcp_StateLASTACK)
      s->rdatalen = 0;
  s->err_msg = _LANG (str);
  s->state   = tcp_StateCLOSED;
  s->ip_type = 0;   /* 2001.1.18 - make it fail tcp_tick() */

#if defined(USE_BSD_FUNC)
  if (_tcp_find_hook)
  {
    Socket *sock = (Socket*) (*_tcp_find_hook) (s);

    if (sock)  /* do a "read-wakeup" on the SOCK_STREAM socket */
    {
      sock->so_state |= SS_CONN_REFUSED;
      if (sock->so_error == 0)
          sock->so_error = ECONNRESET;
    }
  }
#endif
  (void) _tcp_unthread (s);
}

/*
 *  tcp_chksum - Check tcp header checksum
 */
static int tcp_chksum (const in_Header *ip, const tcp_Header *tcp, int len)
{
  tcp_PseudoHeader ph;

  memset (&ph, 0, sizeof(ph));
  ph.src      = ip->source;
  ph.dst      = ip->destination;
  ph.protocol = TCP_PROTO;
  ph.length   = intel16 (len);
  ph.checksum = checksum (tcp, len);

  if (checksum(&ph,sizeof(ph)) == 0xFFFF)
     return (1);

  STAT (tcpstats.tcps_rcvbadsum++);
  if (debug_on)
     outsnl (_LANG("bad tcp checksum"));
  return (0);
}

/*
 *  tcp_rtt_wind - Update retransmission timer, VJ algorithm
 *  and tcp windows.
 */
static void tcp_rtt_wind (tcp_Socket *s)
{
  DWORD timeout;

  /* update our retransmission stuff (Karn algorithm)
   */
  if (s->karn_count == 2)    /* Wake up from slow-start */
  {
#if defined(USE_DEBUG)
    if (debug_on > 1)
       (*_printf)("finally got it safely zapped from %u to ????\r\n",
                  s->unacked);
#endif
  }
  else if (s->vj_last)  /* We expect an immediate response */
  {
    long  dT;      /* time since last (re)transmission */
    DWORD now;

    chk_timeout (0UL);          /* update date/date_ms */
    now = (long) set_timeout (0);
    dT  = (long) get_timediff (now, s->vj_last);

    if (dT >= 0)        /* !!shouldn't this be '> 0' ? */
    {
      dT -= (DWORD)(s->vj_sa >> 3);
      s->vj_sa += (int)dT;

      if (dT < 0)
          dT = -dT;

      dT -= (s->vj_sd >> 2);
      s->vj_sd += (int)dT;      /* vj_sd = RTTVAR, rtt variance */

      if (s->vj_sa > MAX_VJSA)  /* vj_sa = SRTT, smoothed rtt */
          s->vj_sa = MAX_VJSA;
      if (s->vj_sd > MAX_VJSD)
          s->vj_sd = MAX_VJSD;
    }

#if 0 /* !!to-do: use TimeStamp option values */
    if (s->ts_echo && s->ts_echo == s->ts_sent)
    {
      dT = get_timediff (now, s->ts_echo);
    }
    else
#else
    /* only recompute RTT hence RTO after success
     */
    s->rto = tcp_RTO_BASE + (((s->vj_sa >> 2) + (s->vj_sd)) >> 1);
#endif

    tcp_rtt_add (s, s->rto);


#if defined(USE_DEBUG)
    if (debug_on > 1)
       (*_printf)("rto %u  sa %u  sd %u  cwindow %u"
                  "  wwindow %u  unacked %u\r\n",
                  s->rto, s->vj_sa, s->vj_sd, s->cwindow,
                  s->wwindow, s->unacked);
#endif
  }

  s->karn_count = 0;
  if (s->wwindow != 255)
  {
    /* A. Iljasov (iljasov@oduurl.ru) suggested this pre-increment
     */
    if (++s->wwindow >= s->cwindow)
    {
      if (s->cwindow != 255)
          s->cwindow++;
      s->wwindow = 0;    /* mdurkin -- added 95.05.02 */
    }
  }


  /* Restart RTT timer or postpone retransmission
   * based on calculated RTO. Make sure date/date_ms variables
   * are updated close to midnight.
   */
  chk_timeout (0UL);
  timeout = set_timeout (s->rto + tcp_RTO_ADD);

  if (s->rtt_time == 0UL || cmp_timers(s->rtt_time,timeout) < 0)
      s->rtt_time = timeout;

  s->datatimer = 0UL; /* resetting tx-timer, EE 99.08.23 */
}

/*
 *  tcp_upd_wind - Check if receive window needs an update.
 */
static void tcp_upd_wind (tcp_Socket *s, unsigned line)
{
  UINT winfree = s->maxrdatalen - s->rdatalen;

  if (winfree < s->max_seg/2)
     _tcp_send (s, __FILE__, line);  /* update window now */
}

/*
 * TCP option routines.
 * Note: Each of these MUST add multiple of 4 byte of options.
 *
 * Insert MSS option.
 */
static __inline int tcp_opt_maxsegment (tcp_Socket *s, BYTE *opt)
{
  *opt++ = TCPOPT_MAXSEG;    /* option: MAXSEG,length,mss */
  *opt++ = 4;
  *(WORD*) opt = intel16 (s->max_seg);
  return (4);
}

/*
 * Insert TimeStamp option.
 */
static __inline int tcp_opt_timestamp (tcp_Socket *s, BYTE *opt,
                                       DWORD ts_val, DWORD ts_echo)
{
  *opt++ = TCPOPT_NOP;     /* NOP,NOP,TIMESTAMP,length,TSval,TSecho */
  *opt++ = TCPOPT_NOP;
  *opt++ = TCPOPT_TIMESTAMP;   
  *opt++ = 10;
  *(DWORD*) opt = intel (ts_val);  opt += sizeof(ts_val);
  *(DWORD*) opt = intel (ts_echo); opt += sizeof(ts_echo);
  s->ts_sent = ts_val;       /* remember ts_sent */
  return (12);
}

#ifdef NOT_USED
/*
 * Pad options to multiple of 4 bytes.
 */
static __inline int tcp_opt_padding (BYTE *opt, int len)
{
  int i, pad = len % 4;

  for (i = 0; i < pad; i++)
      *opt++ = TCPOPT_NOP;
  return (i);
}

static __inline int tcp_opt_winscale (tcp_Socket *s, BYTE *opt)
{
  *opt++ = TCPOPT_WINDOW;    /* option: WINDOW,length,wscale */
  *opt++ = 4;
  *(WORD*) opt = intel16 (s->send_wscale);
  return (4);
}

static __inline int tcp_opt_sack_ok (tcp_Socket *s, BYTE *opt)
{
  *opt++ = TCPOPT_SACKOK;
  *opt++ = 2;
  *opt++ = TCPOPT_NOP;
  *opt++ = TCPOPT_NOP;
  return (4);
}

static __inline int tcp_opt_sack (tcp_Socket *s, BYTE *opt,
                                  struct SACK_list *sack)
{
  int i, len = 2 + 8 * sack->num_blk;

  *opt++ = TCPOPT_SACK;       /* option: SACK,length,left,right,.. */
  *opt++ = len;
  for (i = 0; i < sack->num_blk; i++)
  {
    *(DWORD*) opt = intel (sack->list[i].left_edge);
    opt += sizeof(DWORD);
    *(DWORD*) opt = intel (sack->list[i].right_edge);
    opt += sizeof(DWORD);
  }
  for (i = 0; i < len % 4; i++)
     *opt++ = TCPOPT_NOP;
  return (len + i);
}
#endif

/*
 * tcp_do_options - Add TCP options to output segment
 */
static __inline int tcp_do_options (tcp_Socket *s, BYTE *opt, BOOL is_syn)
{
  DWORD now = set_timeout (0);
  int   len = 0;

  if (is_syn && !(s->locflags & LF_NOOPT))
  {
    len += tcp_opt_maxsegment (s, opt);

    if (s->locflags & LF_REQ_TSTMP)
       len += tcp_opt_timestamp (s, opt+len, now, 0UL);
#if 0
    if (s->locflags & LF_REQ_SCALE)
       len += tcp_opt_winscale (s, opt+len);

    if (tcp_opt_sackok)
       len += tcp_opt_sack_ok (s, opt+len);
#endif
  }
  else if (!is_syn)
  {
    /* We got a TS option in a previous SYN-ACK or SYN.
     * Send it back unless we send a RST or disallow options.
     * A Win98 host will have 0 in 's->ts_recent'
     */
    if ((s->flags & tcp_FlagRST) == 0 && tcp_opt_timstmp &&
        (s->locflags & (LF_RCVD_TSTMP|LF_NOOPT)) == LF_RCVD_TSTMP)
    {
      len += tcp_opt_timestamp (s, opt, now, s->ts_recent);
      s->locflags &= ~LF_RCVD_TSTMP;  /* don't echo this again */
    }
  }

#ifdef USE_DEBUG
  assert (len == 0 || len % 4 == 0);
#endif
  return (len);
}

/*
 * _tcp_send - Format and send an outgoing segment.
 *             Several packets may be sent depending on peer's window.
 */
int _tcp_send (tcp_Socket *s, char *file, unsigned line)
{
  #include <sys/packon.h>
  struct tcp_pkt {
         in_Header  in;
         tcp_Header tcp;
       } *pkt;
  #include <sys/packoff.h>

  tcp_PseudoHeader ph;

  BOOL         tx_ok;
  BYTE        *data;            /* where to copy user's data */
  mac_address *dst;
  in_Header   *ip;
  tcp_Header  *tcp;
  int          sendtotlen = 0;  /* count of data length we've sent */
  int          senddatalen;     /* how much data in this segment */
  int          startdata;       /* where data starts in tx-buffer */
  int          sendtotdata;     /* total amount of data to send */
  int          tcp_len;         /* total length of TCP segment */
  int          opt_len;         /* total length of TCP options */
  int          pkt_num;         /* 0..s->cwindow-1 */
  int          rtt;

  s->recent = 0;

  dst  = (_pktserial ? NULL : &s->hisethaddr);

⌨️ 快捷键说明

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