pctcp.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 2,251 行 · 第 1/4 页

C
2,251
字号
  pkt  = (struct tcp_pkt*) _eth_formatpacket (dst, IP_TYPE);
  ip   = &pkt->in;
  tcp  = &pkt->tcp;
  data = (BYTE*) (tcp+1);

  if (s->karn_count == 2)   /* doing slow-start */
  {
    sendtotdata = min (s->datalen, s->window);
    startdata = 0;
  }
  else
  {
    /* Morten Terstrup <MorTer@dk-online.dk> found this signed bug
     */
    int size = min (s->datalen, s->window);
    sendtotdata = size - s->unacked;
    if (sendtotdata < 0)
        sendtotdata = 0;
    startdata = s->unacked;
  }

  /* step through our packets
   */
  for (pkt_num = 0; pkt_num < s->cwindow; pkt_num++)
  {
    /* make tcp header
     */
    tcp->srcPort  = intel16 (s->myport);
    tcp->dstPort  = intel16 (s->hisport);
    tcp->seqnum   = intel (s->seqnum + startdata); /* unacked - no longer sendtotlen */
    tcp->acknum   = intel (s->acknum);

    tcp->window   = intel16 (s->maxrdatalen - s->rdatalen);
    tcp->flags    = s->flags;
    tcp->unused   = 0;
    tcp->checksum = 0;
    tcp->urgent   = 0;

    /* Insert any TCP options after header
     */
    if (pkt_num == 0 && (s->flags & (tcp_FlagSYN|tcp_FlagACK)) == tcp_FlagSYN)
    {
      opt_len = tcp_do_options (s, data, TRUE);
      senddatalen = 0;   /* no data, only options */
    }
    else
    {
      int data_free;

      opt_len = tcp_do_options (s, data, FALSE);
      if ((data_free = s->max_seg - opt_len) < 0)
         data_free = 0;
      senddatalen = min (sendtotdata, data_free);
    }

    tcp_len = sizeof(*tcp) + opt_len;
    data   += opt_len;
    tcp->offset = tcp_len/4;

    if (senddatalen > 0)         /* non-SYN packets with data */
    {
      tcp_len += senddatalen;
      if (s->queuelen)
           memcpy (data, s->queue+startdata, senddatalen);
      else memcpy (data, s->data +startdata, senddatalen);
    }

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

    /* make tcp header check-sum
     */
    memset (&ph, 0, sizeof(ph));
    ph.src      = intel (s->myaddr);
    ph.dst      = intel (s->hisaddr);
    ph.protocol = TCP_PROTO;
    ph.length   = intel16 (tcp_len);
    ph.checksum = checksum (tcp, tcp_len);
    tcp->checksum = ~checksum (&ph, sizeof(ph));

    tx_ok = _ip_output (ip, ph.src, ph.dst, TCP_PROTO,
                        s->ttl, s->tos, 0, tcp_len, s, file, line) != 0;
    if (!tx_ok)
    {
      TCP_SENDSOON (s);
      return (-1);
    }

    /* do next packet
     */
    if (senddatalen > 0)
    {
      sendtotlen  += senddatalen;
      startdata   += senddatalen;
      sendtotdata -= senddatalen;
    }
    if (sendtotdata <= 0)
       break;
  }

  s->unacked = startdata;

#if defined(USE_DEBUG)
  if (debug_on > 1)
     (*_printf)(" Sent %u (win %u) bytes in %u (cwin %u) packets with "
                "(%u) unacked  SEQ %lu  line %u\r\n",
                sendtotlen, s->window, pkt_num, s->cwindow,
                s->unacked, s->seqnum, line);
#endif

  s->vj_last = 0UL;
  if (s->karn_count == 2)
  {
    if (s->rto)
         s->rto = (s->rto * 3) / 2;  /* increase by 50% */
    else s->rto = 2*tcp_RTO_ADD;     /* !!was 4 tick */
  }
  else
  {
    /* vj_last nonzero if we expect an immediate response
     */
    if (s->unhappy || s->datalen)
        s->vj_last = set_timeout (0);
    s->karn_count = 0;
  }

  rtt = s->rto + tcp_RTO_ADD;

  s->rtt_time = set_timeout (rtt);

  if (sendtotlen > 0)
     s->rtt_lasttran = s->rtt_time;

  return (sendtotlen);
}


/*
 * Force the peer to send us a segment by sending a keep-alive packet:
 *   <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
 */
int sock_keepalive (sock_type *s)
{
  tcp_Socket *tcp;
  DWORD       ack, seq;
  BYTE        kc;
  int         datalen;

  if (s->tcp.ip_type != TCP_PROTO)
     return (0);

  tcp     = &s->tcp;
  ack     = tcp->acknum;
  seq     = tcp->seqnum;
  kc      = tcp->karn_count;
  datalen = tcp->datalen;

  tcp->acknum     = tcp->seqnum;
  tcp->seqnum     = tcp->unacked - 1;
  tcp->flags      = tcp_FlagACK;
  tcp->karn_count = 2;
  tcp->datalen    = 0;
  (void) TCP_SEND (tcp);

  tcp->acknum     = ack;
  tcp->seqnum     = seq;
  tcp->karn_count = kc;
  tcp->datalen    = datalen;

  STAT (tcpstats.tcps_keepprobe++);
  STAT (tcpstats.tcps_keeptimeo++);
  return (1);
}
#endif  /* !USE_UDP_ONLY */


/*
 * sock_mode - set binary or ascii - affects sock_gets, sock_dataready
 *           - set udp checksums
 */
WORD sock_mode (sock_type *s, WORD mode)
{
  if (s->tcp.ip_type == TCP_PROTO || s->tcp.ip_type == UDP_PROTO)
  {
    s->tcp.sockmode = (s->tcp.sockmode & 0xFFFC) | mode;
    return (s->tcp.sockmode);
  }
  return (0);
}

/*
 * sock_yield - enable user defined yield function
 */
int sock_yield (tcp_Socket *s, void (*fn)())
{
  if (s)
       s->usr_yield = fn;
  else system_yield = fn;
  return (0);
}


void sock_abort (sock_type *s)
{
  switch (s->tcp.ip_type)
  {
#if !defined(USE_UDP_ONLY)
    case TCP_PROTO:
         tcp_abort (&s->tcp);
         break;
#endif
    case UDP_PROTO:
         udp_close (&s->udp);
         break;
    case IP_TYPE:
         s->raw.ip_type = 0;
         s->raw.used    = 0;
         break;
  }
}

#if defined(USE_BSD_FUNC)
/*
 * Read data from a raw-socket. Don't copy IP-header to buf.
 */
static int raw_read (raw_Socket *raw, BYTE *buf, int maxlen)
{
  int len = 0;

  if (raw->used)
  {
    int   hlen = in_GetHdrLen (&raw->ip);
    BYTE *data = (BYTE*)&raw->ip + hlen;

    len = intel16 (raw->ip.length) - hlen;
    len = min (len, maxlen);
    memcpy (buf, data, len);
    raw->used = 0;
  }
  return (len);
}
#endif

/*
 * sock_read - read a socket with maximum 'maxlen' bytes
 *           - busywaits until 'buf' is full (and call 's->usr_yield')
 *           - returns count ( <= maxlen) also when connection gets closed
 */
int sock_read (sock_type *s, BYTE *buf, int maxlen)
{
  int count = 0;

  do
  {
    int len = 0;
    int raw = 0;

    switch (s->udp.ip_type)
    {
#if !defined(USE_UDP_ONLY)
      case TCP_PROTO:
           len = tcp_read (&s->tcp, buf, maxlen);
           break;
#endif
      case UDP_PROTO:
           len = udp_read (&s->udp, buf, maxlen);
           break;

#if defined(USE_BSD_FUNC)
      case IP_TYPE:
           raw = TRUE;
           len = raw_read (&s->raw, buf, maxlen);
           break;
#endif
    }

    if (len < 1)
    {
      if (!tcp_tick(s))
         return (count);
    }
    else
    {
      count  += len;
      buf    += len;
      maxlen -= len;
    }
    if (maxlen > 0 && !raw && s->tcp.usr_yield) /* yield only when room */
      (*s->tcp.usr_yield)();                    /* 99.07.01 EE */
  }
  while (maxlen);
  return (count);
}

/*
 * sock_fastread - read a socket with maximum 'len' bytes
 *               - does not busywait until buffer is full
 */
int sock_fastread (sock_type *s, BYTE *buf, int len)
{
  if (s->udp.ip_type == UDP_PROTO)
     return udp_read (&s->udp, buf, len);

#if !defined(USE_UDP_ONLY)
  if (s->tcp.ip_type == TCP_PROTO || s->tcp.rdatalen > 0)
     return tcp_read (&s->tcp, buf, len);
#endif

#if defined(USE_BSD_FUNC)
  if (s->raw.ip_type == IP_TYPE)
     return raw_read (&s->raw, buf, len);
#endif

  return (-1);
}


/*
 * sock_write - writes data and returns length written
 *            - send with PUSH-bit (flush data)
 *            - repeatedly calls s->usr_yield
 */
int sock_write (sock_type *s, const BYTE *data, int len)
{
  int chunk   = len;
  int written = 0;

  while (chunk > 0)
  {
    switch (s->udp.ip_type)
    {
#if !defined(USE_UDP_ONLY)
      case TCP_PROTO:
           s->tcp.flags |= tcp_FlagPUSH;
           written = tcp_write (&s->tcp, data, chunk);
           break;
#endif           
      case UDP_PROTO:
           chunk = min (mtu - sizeof(in_Header) - sizeof(udp_Header), chunk);
           written = udp_write (&s->udp, data, chunk);
           break;

#if defined(USE_BSD_FUNC)
      case IP_TYPE:
           return (0);   /* not supported yet */
#endif
      default:           /* EE 99.06.14 */
           return (0);
    }

    if (written < 0)
    {
      s->udp.err_msg = _LANG("Tx Error");
      return (0);
    }
    data  += written;
    chunk -= written;

    if (s->udp.usr_yield)
      (*s->udp.usr_yield)();

    if (!tcp_tick(s))
       return (0);
  }
  return (len);
}

/*
 * sock_fastwrite
 *
 * NOTE: for UDP, assumes data fits in one datagram, else only the first
 *     fragment will be sent!  Because MTU is used for splits,
 *     by default the max data size is MTU-(20+sizeof(udp_Header)) = 548
 *     for a non-fragged datagram.
 */
int sock_fastwrite (sock_type *s, const BYTE *data, int len)
{
  switch (s->udp.ip_type)
  {
    case UDP_PROTO:
         len = min (mtu - sizeof(in_Header) - sizeof(udp_Header), len);
         len = udp_write (&s->udp, data, len);
         return (len < 0 ? 0 : len);

#if !defined(USE_UDP_ONLY)
    case TCP_PROTO:
         len = tcp_write (&s->tcp, data, len);
         return (len < 0 ? 0 : len);
#endif
  }
  return (0);
}


int sock_enqueue (sock_type *s, const BYTE *data, int len)
{
  if (len <= 0)
     return (0);

  if (s->udp.ip_type == UDP_PROTO)
  {
    int written = 0;
    int total   = 0;
    do
    {
      len = min (mtu - sizeof(in_Header) - sizeof(udp_Header), len);
      written = udp_write (&s->udp, data, len);
      if (written < 0)
      {
        s->udp.err_msg = _LANG("Tx Error");
        break;
      }
      data  += written;
      len   -= written;
      total += written;
    }
    while (len > 0);
    return (total);
  }

#if !defined(USE_UDP_ONLY)
  if (s->tcp.ip_type == TCP_PROTO)
  {
    s->tcp.queue    = data;
    s->tcp.queuelen = len;
    s->tcp.datalen  = len;
    return TCP_SEND (&s->tcp);
  }
#endif
  return (0);
}

#if !defined(USE_UDP_ONLY)
void sock_noflush (sock_type *s)
{
  if (s->tcp.ip_type == TCP_PROTO)
  {
    s->tcp.flags &= ~tcp_FlagPUSH;
    s->tcp.sockmode |= TCP_LOCAL;
  }
}

/*
 * sock_flush - Send pending TCP data
 */
void sock_flush (sock_type *s)
{
  if (s->tcp.ip_type == TCP_PROTO)
  {
    tcp_Socket *tcp = &s->tcp;

    tcp->sockmode &= ~TCP_LOCAL;
    if (tcp->datalen > 0)
    {
      tcp->flags |= tcp_FlagPUSH;
      if (s->tcp.unacked == 0)  /* !! S. Lawson - only if data not moving */
         (void) TCP_SEND (tcp);
    }
  }
}

/*
 * sock_flushnext - cause next transmission to have a flush
 */
void sock_flushnext (sock_type *s)
{
  if (s->tcp.ip_type == TCP_PROTO)
  {
    s->tcp.flags |= tcp_FlagPUSH;
    s->tcp.sockmode &= ~TCP_LOCAL;
  }
}
#endif  /* !USE_UDP_ONLY */


int sock_close (sock_type *s)
{
  switch (s->tcp.ip_type)
  {
    case UDP_PROTO:
         udp_close (&s->udp);
         break;

#if !defined(USE_UDP_ONLY)
    case TCP_PROTO:
         _tcp_close (&s->tcp);
         (void) tcp_tick (s);
         break;
#endif
  }
  return (0);
}

#if !defined(USE_UDP_ONLY)

/*
 * Round trip timing cache routines.
 * These functions implement a very simple system for keeping track of
 * network performance for future use in new connections.
 * The emphasis here is on speed of update (rather than optimum cache
 * hit ratio) since tcp_rtt_add() is called every time a TCP connection
 * updates its round trip estimate. Note: 'rto' is either in ticks or
 * milli-sec depending on if PC has an 8254 Time chip.
 *
 * These routines are modified versions from KA9Q by Phil Karn.
 */
static struct tcp_rtt rtt_cache [RTTCACHE];

static void tcp_rtt_add (tcp_Socket *s, UINT rto)
{
  struct tcp_rtt *rtt;
  DWORD  addr = s->hisaddr;

  if (~addr & ~sin_mask)  /* 0.0.0.0 or broadcast addresses? */
     return;

  rtt = &rtt_cache [(WORD)addr % RTTCACHE];

  /* Cache-slot is vacant or we're updating previous RTO
   * for same peer
   */
  if (!rtt->ip || rtt->ip == addr)
  {
    rtt->ip  = addr;
    rtt->rto = rto;
    STAT (tcpstats.tcps_cachedrtt++);
  }
}

static UINT tcp_rtt_get (tcp_Socket *s)
{
  struct tcp_rtt *rtt = &rtt_cache [(WORD)s->hisaddr % RTTCACHE];

  if (s->hisaddr && rtt->ip == s->hisaddr && rtt->rto > 0)
  {
#if defined(USE_DEBUG) && !defined(_MSC_VER) /* MSC6 crashes below */
    char buf[20];
    dbug_write_raw ("\r\nRTT-cache: host ");
    dbug_write_raw (_inet_ntoa(buf, rtt->ip));
    dbug_write_raw (": ");
    dbug_write_raw (time_str(rtt->rto));
    dbug_write_raw ("s\r\n\r\n");
#endif

    STAT (tcpstats.tcps_usedrtt++);
    return (rtt->rto);
  }
  return (0);
}

static void tcp_rtt_clr (tcp_Socket *s)
{
  struct tcp_rtt *rtt = &rtt_cache [(WORD)s->hisaddr % RTTCACHE];

  if (s->hisaddr && rtt->ip == s->hisaddr)
  {
    rtt->rto = 0;
    rtt->ip  = 0;
  }
}
#endif /* !USE_UDP_ONLY */

⌨️ 快捷键说明

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