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

📄 pctcp.c

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

/*
 *  PCTCP - the true worker of Waterloo TCP
 *        - contains all opens, closes, major read/write routines and
 *          basic IP handler for incomming packets
 *        - NOTE: much of the TCP/UDP/IP layering is done at the data
 *          structure level, not in separate routines or tasks
 *
 */

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <dos.h>

#include "copyrigh.h"
#include "wattcp.h"
#include "wattcpd.h"
#include "chksum.h"
#include "strings.h"
#include "language.h"
#include "udp_dom.h"
#include "bsdname.h"
#include "pcstat.h"
#include "pcconfig.h"
#include "pcqueue.h"
#include "pcsed.h"
#include "pcpkt.h"
#include "pcicmp.h"
#include "pcigmp.h"
#include "pcmulti.h"
#include "pcdbug.h"
#include "pcdhcp.h"
#include "pcbsd.h"
#include "pcarp.h"
#include "ip_out.h"
#include "misc.h"
#include "fragment.h"
#include "pppoe.h"
#include "tcp_fsm.h"
#include "pctcp.h"

#if defined(USE_BSD_FUNC)
#include "socket.h"
#endif

#ifndef __inline  /* normally in <sys/cdefs.h> */
#define __inline   
#endif

/*
 * These are hooks to prevent the BSD-socket API being linked in
 * by default. These function pointers are only set from the BSD
 * functions when needed; `_raw_ip_hook' is set to filter SOCK_RAW
 * packets, `_tcp_syn_hook' is set to filter incoming SYN packets
 * for SOCK_STREAM packets used in `accept()'. And '_tcp_find_hook'
 * is set to `sock_find_tcp()' when allocating SOCK_STREAM sockets.
 */
int   (*_raw_ip_hook)  (const in_Header *)  = NULL;
int   (*_tcp_syn_hook) (tcp_Socket **)      = NULL;
void *(*_tcp_find_hook) (const tcp_Socket*) = NULL;

char   hostname[MAX_HOSTLEN+1] = "random-pc";

int    mss          = ETH_MAX_DATA - sizeof(tcp_Header) - sizeof(in_Header);
int    mtu          = ETH_MAX_DATA;
int    mtu_discover = 0;   /* to-do */

int    block_tcp    = 0;   /* when application handles tcp itself  */
int    block_udp    = 0;   /*                          udp itself  */
int    block_icmp   = 0;   /*                          icmp itself */
int    block_ip     = 0;   /*                          ip itself   */

DWORD  my_ip_addr   = 0L;          /* our IP address */
DWORD  sin_mask     = 0xFFFFFF00L; /* our net-mask, 255.255.255.0 */

DebugProc _dbugxmit = NULL;
DebugProc _dbugrecv = NULL;

udp_Socket *_udp_allsocs = NULL;   /* list of udp-sockets */


/*
 * Prototypes and local data
 */

#if !defined(USE_UDP_ONLY)   /* not used for UDP/IP */

  /* TCP timer values
   */
  int tcp_OPEN_TO     = DEF_OPEN_TO;
  int tcp_CLOSE_TO    = DEF_CLOSE_TO;
  int tcp_RTO_ADD     = DEF_RTO_ADD;
  int tcp_RTO_BASE    = DEF_RTO_BASE;
  int tcp_RST_TIME    = DEF_RST_TIME;
  int tcp_RETRAN_TIME = DEF_RETRAN_TIME;

  /* TCP option config flags.
   */
  int tcp_opt_timstmp = 0;
  int tcp_opt_wscale  = 0;
  int tcp_opt_sackok  = 0;

  /* Misc TCP values
   */
  int tcp_nagle     = 1;
  int tcp_keepalive = 30;

  tcp_Socket *_tcp_allsocs  = NULL; /* list of tcp-sockets */

  static tcp_Socket *tcp_findseq (const in_Header *ip, const tcp_Header *tcp);

  static void tcp_sockreset(tcp_Socket *s, int proxy);
  static void tcp_rtt_wind (tcp_Socket *s);
  static void tcp_upd_wind (tcp_Socket *s, unsigned line);
  static int  tcp_chksum   (const in_Header *ip, const tcp_Header *tcp, int len);
  
  static void tcp_rtt_add  (tcp_Socket *s, UINT rto);
  static void tcp_rtt_clr  (tcp_Socket *s);
  static UINT tcp_rtt_get  (tcp_Socket *s);
#endif

static void udp_close   (udp_Socket *s);
static void (*system_yield)(void) = NULL;


/*
 * Passive open: listen for a connection on a particular port
 */
int udp_listen (udp_Socket *s, WORD lport, DWORD ina, WORD port, ProtoHandler handler)
{
  udp_close (s);
  watt_largecheck (s, sizeof(*s), __FILE__, __LINE__);
  memset (s, 0, sizeof(*s));

  s->rdata        = &s->rddata[0];
  s->maxrdatalen  = udp_MaxBufSize;
  s->ip_type      = UDP_PROTO;
  s->myport       = findfreeport (lport, 0); /* get a nonzero port val */
  s->hisport      = port;
  s->hisaddr      = ina;
  s->ttl          = _default_ttl;
  s->protoHandler = handler;
  s->usr_yield    = system_yield;
  s->safetysig    = SAFETYUDP;               /* insert into chain */
  s->next         = _udp_allsocs;
  _udp_allsocs    = s;

  return (1);
}

/*
 * Active open: open a connection on a particular port
 */
int udp_open (udp_Socket *s, WORD lport, DWORD ip, WORD port, ProtoHandler handler)
{
  BOOL bcast = (ip == (DWORD)-1) ||
               (~ip & ~sin_mask) == 0;

  udp_close (s);
  watt_largecheck (s, sizeof(*s), __FILE__, __LINE__);
  memset (s, 0, sizeof(*s));

  if (ip - my_ip_addr <= multihomes)
     return (0);

  s->rdata       = &s->rddata[0];
  s->maxrdatalen = udp_MaxBufSize;
  s->ip_type     = UDP_PROTO;
  s->myport      = findfreeport (lport, 0);
  s->myaddr      = my_ip_addr;
  s->ttl         = _default_ttl;

  if (bcast || !ip)      /* check for broadcast */
  {
    memset (s->hisethaddr, 0xFF, sizeof(eth_address));
    if (!ip)
       ip = (DWORD)-1;   /* make s->hisaddr = 255.255.255.255 */
  }

#if defined(USE_MULTICAST)
  else if (is_multicast(ip))   /* check for multicast */
  {
    multi_to_eth (ip, (BYTE*)&s->hisethaddr[0]);
    s->ttl = 1;     /* so we don't send worldwide as default */
  }
#endif
  else if (!_arp_resolve(ip,&s->hisethaddr,0))
          return (0);
 
  s->hisaddr      = ip;
  s->hisport      = port;
  s->protoHandler = handler;
  s->usr_yield    = system_yield;
  s->safetysig    = SAFETYUDP;
  s->next         = _udp_allsocs;
  _udp_allsocs    = s;
  return (1);
}

/*
 *  Since UDP is stateless, simply reclaim the local-port and
 *  unthread the socket from the list.
 */
static void udp_close (udp_Socket *ds)
{
  udp_Socket *s, *prev;

  for (s = prev = _udp_allsocs; s; prev = s, s = s->next)
  {
    if (ds != s)
       continue;

    (void) reuse_localport (s->myport);

    if (s == _udp_allsocs)
         _udp_allsocs = s->next;
    else prev->next   = s->next;
    if (s->err_msg == NULL)
        s->err_msg = _LANG("UDP Close called");
  }
}

/*
 * Set the TTL on an outgoing UDP datagram.
 */
void udp_SetTTL (udp_Socket *s, BYTE ttl)
{
  s->ttl = ttl;
}


#if !defined(USE_UDP_ONLY)

/*
 * Actively open a TCP connection to a particular destination.
 *  - 0 on error
 *
 * 'lport' is local port to associate with the connection.
 * 'rport' is remote port for same connection
 */
int tcp_open (tcp_Socket *s, WORD lport, DWORD ina, WORD rport, ProtoHandler handler)
{
  UINT rtt;

  watt_largecheck (s, sizeof(*s), __FILE__, __LINE__);
  (void) _tcp_unthread (s);       /* just in case not totally closed */
  memset (s, 0, sizeof(*s));

  if ((ina - my_ip_addr <= multihomes) || is_multicast(ina))
     return (0);

  if (!_arp_resolve(ina,&s->hisethaddr,0))
     return (0);

  s->rdata        = &s->rddata[0];
  s->maxrdatalen  = tcp_MaxBufSize;
  s->ip_type      = TCP_PROTO;
  s->max_seg      = mss;        /* to-do !!: use mss from setsockopt() */
  s->state        = tcp_StateSYNSENT;
  s->timeout      = set_timeout (tcp_LONGTIMEOUT);

  /* to-do !!: use TCP_NODELAY set in setsockopt()
   */
  s->sockmode     = tcp_nagle ? TCP_MODE_NAGLE : TCP_MODE_NONAGLE;
  s->cwindow      = 1;
  s->wwindow      = 0;                      /* slow start VJ algorithm */
  s->vj_sa        = INIT_VJSA;
  s->rto          = tcp_OPEN_TO;            /* added 14-Dec 1999, GV   */
  s->myaddr       = my_ip_addr;
  s->myport       = findfreeport (lport,1); /* get a nonzero port val  */
  s->locflags     = LF_LINGER;              /* close via TIMEWT state  */
  if (tcp_opt_timstmp)
     s->locflags |= LF_REQ_TSTMP;           /* use timestamp option */

  s->ttl          = _default_ttl;
  s->hisaddr      = ina;
  s->hisport      = rport;
  s->seqnum       = INIT_SEQ();
  s->flags        = tcp_FlagSYN;
  s->unhappy      = TRUE;
  s->protoHandler = handler;
  s->usr_yield    = system_yield;

  s->safetysig    = SAFETYTCP;              /* marker signatures */
  s->safetytcp    = SAFETYTCP;
  s->next         = _tcp_allsocs;           /* insert into chain */
  _tcp_allsocs    = s;

  (void) TCP_SEND (s);                      /* send opening SYN */
 
  /* find previous RTT replacing RTT set in tcp_send() above
   */
  if ((rtt = tcp_rtt_get(s)) > 0)
       s->rtt_time = set_timeout (rtt);
  else s->rtt_time = set_timeout (tcp_OPEN_TO);
  return (1);
}

/*
 * Passive open: listen for a connection on a particular port
 */
int tcp_listen (tcp_Socket *s, WORD lport, DWORD ina, WORD port, ProtoHandler handler, WORD timeout)
{
  watt_largecheck (s, sizeof(*s), __FILE__, __LINE__);
  (void) _tcp_unthread (s);    /* just in case not totally closed */
  memset (s, 0, sizeof(*s));

  if (is_multicast(ina))
     return (0);

  s->rdata        = &s->rddata[0];
  s->maxrdatalen  = tcp_MaxBufSize;
  s->ip_type      = TCP_PROTO;
  s->max_seg      = mss;        /* to-do !!: use mss from setsockopt() */
  s->cwindow      = 1;
  s->wwindow      = 0;               /* slow start VJ algorithm */
  s->vj_sa        = INIT_VJSA;
  s->state        = tcp_StateLISTEN;
  s->locflags     = LF_LINGER;

  s->myport       = findfreeport (lport, 0);
  s->hisport      = port;
  s->hisaddr      = ina;
  s->seqnum       = INIT_SEQ();
  s->unhappy      = FALSE;
  s->ttl          = _default_ttl;
  s->protoHandler = handler;
  s->usr_yield    = system_yield;
  s->safetysig    = SAFETYTCP;      /* marker signatures */
  s->safetytcp    = SAFETYTCP;
  s->next         = _tcp_allsocs;   /* insert into chain */
  _tcp_allsocs    = s;

  if (timeout != 0)
     s->timeout = set_timeout (1000 * timeout);
  return (1);
}

/*
 *  Send a FIN on a particular port -- only works if it is open.
 *  Must still allow receives
 */
void _tcp_close (tcp_Socket *s)
{
  if (s->ip_type != TCP_PROTO)
     return;

  if (s->state == tcp_StateESTAB ||
      s->state == tcp_StateESTCL ||
      s->state == tcp_StateSYNREC)
  {
    if (s->datalen)      /* must first flush all Tx data */
    {
      s->flags |= (tcp_FlagPUSH | tcp_FlagACK);
      if (s->state < tcp_StateESTCL)
      {
        s->state = tcp_StateESTCL;
        TCP_SENDSOON (s);
      }
    }
    else  /* really closing */
    {
      s->flags = (tcp_FlagACK | tcp_FlagFIN);
      if (s->err_msg == NULL)
          s->err_msg = _LANG("Connection closed normally");

      s->state    = tcp_StateFINWT1;
      s->timeout  = set_timeout (tcp_TIMEOUT);
      s->rtt_time = 0UL;   /* stop RTT timer */
      (void) TCP_SEND (s);
    }
    s->unhappy = TRUE;
  }
  else if (s->state == tcp_StateCLOSWT)
  {
   /* need to ACK the FIN and get on with it
    */
    s->timeout = set_timeout (tcp_LASTACK_TIME); /* Added AGW 6 Jan 2001 */
    s->state   = tcp_StateLASTACK;
    s->flags  |= tcp_FlagFIN;
    (void) TCP_SEND (s);
    s->unhappy = TRUE;
  }
  else if (s->state == tcp_StateSYNSENT)   /* unlink failed connection */
  {
    s->state = tcp_StateCLOSED;
    maybe_reuse_lport (s);
    (void) _tcp_unthread (s);
  }
}

/*
 * Abort a tcp connection
 */
void tcp_abort (tcp_Socket *s)
{
  if (s->err_msg == NULL)
      s->err_msg = _LANG("TCP Abort");

  if (s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED)
  {
    s->flags   = (tcp_FlagRST | tcp_FlagACK);
    s->unhappy = TRUE;
    if (s->state <= tcp_StateSYNREC)
    {
      s->rtt_time = 0UL; /* Stop RTT timer */
      tcp_rtt_clr (s);   /* Clear cached RTT */
    }
    (void) TCP_SEND (s);
  }
  s->unhappy = FALSE;
  s->datalen = 0;        /* discard Tx buffer, but not Rx buffer */
  s->ip_type = 0;

  maybe_reuse_lport (s);
  (void) _tcp_unthread (s);
}

/*
 * _tcp_sendsoon - schedule a transmission pretty soon.
 *  - this one has an imperfection at midnight, but it
 *    is not significant to the connection performance.
 *
 *    gv: Added - 5 May 2000: Relax retransmission period to
 *        tcp_CLOSE_TO when CLOSEWT state is entered.
 *        Relax retransmission period to tcp_OPEN_TO in
 *        SYNSENT state.
 */
int _tcp_sendsoon (tcp_Socket *s, char *file, unsigned line)
{
  DWORD timeout;

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

  if (s->state >= tcp_StateCLOSWT)
       timeout = set_timeout (tcp_CLOSE_TO);
  else timeout = set_timeout (tcp_RTO_BASE);

  if (s->rto <= tcp_RTO_BASE && s->recent == 0 &&
      cmp_timers(s->rtt_time,timeout) <= 0)
  {                         /* !! was == */
    int rc;

    s->karn_count = 0;
    rc = _tcp_send (s, file, line);
    s->recent = 1;
    return (rc);
  } 

  if ((s->unhappy || s->datalen > 0 || s->karn_count == 1) &&
      (s->rtt_time && cmp_timers(s->rtt_time,timeout) < 0))
     return (0);

  if (s->state == tcp_StateSYNSENT)  /* relaxed in SYNSENT state */
       s->rtt_time = set_timeout (tcp_OPEN_TO);
  else s->rtt_time = set_timeout (tcp_RTO_BASE + (s->rto >> 4));

  s->karn_count = 1;

  return (0);
}

/*
 * Unthread a socket from the tcp socket list, if it's there
 */
tcp_Socket *_tcp_unthread (tcp_Socket *ds)
{
  tcp_Socket *s, *prev;
  tcp_Socket *next = NULL;

  for (s = prev = _tcp_allsocs; s; prev = s, s = s->next)
  {
    if (ds != s)
       continue;

    if (s == _tcp_allsocs)
         _tcp_allsocs = s->next;
    else prev->next   = s->next;
    next = s->next;
  }

  if (ds->rdatalen == 0 || (ds->state > tcp_StateESTCL))
      ds->ip_type = 0;             /* fail further I/O */
  ds->state = tcp_StateCLOSED;     /* tcp_tick needs this */

  return (next);
}

/*
 * Returns 1 if connection is established
 */
int tcp_established (tcp_Socket *s)
{
  return (s->state >= tcp_StateESTAB);
}

/*
 *  tcp_handler - All tcp input processing is done from here.
 */
static tcp_Socket *tcp_handler (const in_Header *ip, BOOL broadcast)
{
  tcp_Header *tcp;
  tcp_Socket *s;
  int        len;
  BYTE       flags;
  DWORD      source = intel (ip->source);
  DWORD      destin = intel (ip->destination);
  WORD       dstPort, srcPort;

  if (broadcast || block_tcp ||
      !is_local_addr(destin) || is_multicast(source))
  {
    DEBUG_RX (NULL, ip);
    if (!block_tcp)
       STAT (tcpstats.tcps_drops++);
    return (NULL);
  }

  len   = in_GetHdrLen (ip);                /* len of IP header  */
  tcp   = (tcp_Header*) ((BYTE*)ip + len);  /* tcp frame pointer */
  len   = intel16 (ip->length) - len;       /* len of tcp+data   */
  flags = tcp->flags & tcp_FlagMASK;        /* get TCP flags     */

  if (!tcp_chksum(ip,tcp,len))
  {
    DEBUG_RX (NULL, ip);
    return (NULL);
  }

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

  /* demux to active sockets
   */
  for (s = _tcp_allsocs; s; s = s->next)
  {
    if (s->safetysig != SAFETYTCP || s->safetytcp != SAFETYTCP)
    {
      outsnl (_LANG("tcp-socket error in tcp_handler()"));
      DEBUG_RX (s, ip);
      return (NULL);
    }

    if (s->hisport            &&   /* not a listening socket */
        destin  == s->myaddr  &&   /* addressed to my IP */
        source  == s->hisaddr &&   /* and from my peer address */
        dstPort == s->myport  &&   /* addressed to my local port */
        srcPort == s->hisport)     /* and from correct remote port */
      break;
  }

  if (!s && (flags & tcp_FlagSYN))
  {
    /* demux to passive (listening) sockets, must be a new session
     */
    for (s = _tcp_allsocs; s; s = s->next)
        if (s->hisport == 0 &&        /* =0, listening socket */
            dstPort    == s->myport)  /* addressed to my local port */

⌨️ 快捷键说明

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