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

📄 pctcp.c

📁 dos下开发TCP网络的库文件部分
💻 C
📖 第 1 页 / 共 5 页
字号:
/* DEBUG flag may be set for my internal playing */

/*
#define DEBUG
*/

/*
 *  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 <copyright.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <mem.h>
#include <dos.h>
#include <values.h>

#include "wattcp.h"
#include "elib.h"

static void udp_handler(in_Header *ip);
static udp_write(udp_Socket *s, byte *datap, int len, word offset);
static int udp_read(udp_Socket *s, byte *datap, int maxlen);
static void tcp_Retransmitter(void);


#define TCP_LOCAL 0x4000
#define TCP_SAWCR 0x2000                // S. Lawson

/* statics */
//static tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len);
static void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len, // 94.11.19
                                    tcp_PseudoHeader *ph, word *flags); // S. Lawson

static char far *mono = (char far *)0xb0000000L;
static char far *colour = (char far *)0xb8000000L;

static initialized = 0;
void (*system_yield)() = NULL;      /* 2000.4.14 EE */
extern int multihomes;
extern word _pktipofs;
void (*_dbugxmit)( sock_type *s, in_Header *inp, void *phdr, unsigned line ) = NULL;
void (*_dbugrecv)( sock_type *s, in_Header *inp, void *phdr, unsigned line ) = NULL;
void (*wattcpd)(void) = NULL;

char *_hostname = "012345678901234567890123456789012345678901234567890";

word _mss = ETH_MSS;            // maximum size of *IP DATAGRAM*
word sock_data_timeout = 120;  /* after 2 minutes we give up EE 99.08.23 */

char *_wattcp = WATTCP_C;

static void tcp_handler(in_Header *ip);
static void udp_handler(in_Header *ip);

static void tcp_unthread(tcp_Socket *ds);
static void tcp_abort(tcp_Socket *s);
void tcp_sendsoon(tcp_Socket *s );
static void tcp_send(tcp_Socket *s, int line);
static void tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp);
static udp_close(udp_Socket *ds);

// AGW
// unsigned long later than for seq and ack comparisons -- allow for roll over
#define laterthan(x,y) ((long)((x)-(y))>0)

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

/*
 * sock_mode - set binary or ascii - affects sock_gets, sock_dataready
 *           - set udp checksums
 */
word sock_mode( sock_type *s, word mode )
{
     return( s->tcp.sock_mode = (s->tcp.sock_mode & 0xfffc) | mode);
}

/*
 * ip user level timer stuff
 *   void ip_timer_init( void *s, int delayseconds )
 *   int  ip_timer_expired( void *s )
 *      - 0 if not expired
 */
static unsigned long far *realclock = (unsigned long far *)0x000046cL;
#define MAXTICKS 0x1800b0L

void ip_timer_init( sock_type *s , int delayseconds )
{
    if (delayseconds)
        s->tcp.usertimer = set_timeout( delayseconds );
    else
        s->tcp.usertimer = 0;
}

int ip_timer_expired( sock_type *s )
{
    if (! s->tcp.usertimer)     /* cannot expire */
        return( 0 );
    return( chk_timeout( s->tcp.usertimer));
}

longword MsecClock( void )
{
    return( (*realclock) * 055L);
}

static long make_timeout( word timeout )
{
    if ( timeout ) return( set_timeout( timeout ));
    return( 0 );
}

#ifdef NOTUSED    /* 94.11.27 -- not used? */
/*
 * check_timeout - test agains timeout clock - account for overflow
 */
static int check_timeout( unsigned long timeout )
{
    if (timeout) return( chk_timeout( timeout ));
    return( 0 );
}
#endif

/*
 * Local IP address
 */
longword my_ip_addr = 0L;       /* for external references */
longword sin_mask = 0xfffffe00L;
longword sin_gate = 0x0;


/*
 * IP identification numbers
 */

static int ip_id = 0;                   /* packet number */
static int next_tcp_port = 1024;        /* auto incremented */
static int next_udp_port = 1024;
//static
tcp_Socket *tcp_allsocs = NULL;
static udp_Socket *udp_allsocs = NULL;

/* Timer definitions */
#define RETRAN_STRAT_TIME  1     /* in ticks - how often do we check retransmitter tables*/
#define tcp_RETRANSMITTIME 3     /* interval at which retransmitter is called */
#define tcp_LONGTIMEOUT 31       /* timeout for opens */
#define tcp_TIMEOUT 13           /* timeout during a connection */
#define LASTACK_TIMEOUT 10              // timeout in the LASTACK state added AGW 5th Jan 2001

// S. Lawson - define a short TIME_WAIT timeout that can be set in the
//             makefile.  It should be from .5 to 4 minutes (2MSL) but it's
//             not really practical for us.  2 secs will hopefully handle the
//             case where ACK must be retransmitted, but can't protect future
//             connections on the same port from old packets.
#if !defined(TW_TO)
#define TW_TO 2
#endif

word debug_on = 0;

/*
 * look for bugs
 */
int tcp_checkfor( sock_type *t )
{
    tcp_Socket *p;

    for ( p = tcp_allsocs ; p ; p = p->next )
        if ( p == (tcp_Socket *)t ) return( 1 );
    return( 0 );
}

/*
 * Shut down the card and all services
 */
void tcp_shutdown( void )
{
    while (tcp_allsocs)
        tcp_abort( tcp_allsocs );
    _eth_release();
    initialized = 0;
}

// S. Lawson - keep an exiting tcp_init()
void tcp_init( void )
{
   int r;
   r=tcp_init_noexit();
   if (r) exit(r);
}

/*
 * tcp_init - Initialize the tcp implementation
 *          - may be called more than once without hurting
 */
int tcp_init_noexit( void )             // S. Lawson
{
    extern int _arp_last_gateway;
    extern int _last_nameserver;

    if (!initialized) {
        /* initialize ethernet interface */
        initialized = 1;
// S. Lawson    _eth_init();
        if (_eth_init()) return 1;      // S. Lawson

        /* reset the various tables */
        _arp_last_gateway = 0;  /* reset the gateway table */
        _last_nameserver = 0;   /* reset the nameserver table */
        _last_cookie = 0;       /* eat all remaining crumbs */
        *_hostname = 0;         /* reset the host's name */


        _eth_free( 0 );
        next_udp_port = next_tcp_port = 1024 + ((int)(*realclock >> 7 )& 0x1ff);
    }
    return 0;                   // S. Lawson
}

// S. Lawson - initialize the port number counters
void tcp_set_ports(word tcp_base, word udp_base) {
    if (tcp_base) next_tcp_port=(int) tcp_base;
    if (udp_base) next_udp_port=(int) udp_base;
}

// S. Lawson - return current port number counters
void tcp_get_ports(word *tcp_base, word *udp_base) {
    if (tcp_base) *tcp_base=(word) next_tcp_port;
    if (udp_base) *udp_base=(word) next_udp_port;
}

/*
 * Checks for bugs when compiling in large model C compiler
 *
 * Borland C uses a 4K stack by default.  In all memory models the
 * stack grows down toward the heap.
 *
 * If you accidentally place tcp_Socket onto the stack (like by making
 * it an automatic variable), then you will have already used up that
 * whole 4K and then some!
 *
 * In large model, this will mess up the data space in a major way
 * because the stack starts at SS:_stklen, or SS:1000, so you will
 * wrap the SP pointer back around to FFFE and start writing over
 * the far heap.  Yuck.
 *
 * In small model it usually doesn't kill your application because
 * you would have to be down to your last 4K of memory and this is
 * not as common.
 *
 * The solutions: declare your sockets as static, or put them on the
 * heap, or bump up your stack size by using the global special variable:
 *
 * unsigned _stklen = 16536;    // set stack to 16 k
 */
static void largecheck( void *s, int size )
{
#ifdef __TURBOC__
    if ( (word)(FP_OFF(s)) > (word)(-size)) {
        outs("ERROR: user stack size error\n");
        exit( 3 );
    }
#endif
}

/*
 * findfreeport - return unused local port
 *              - oldport = 0:normal port, 1:special port (513-1023)
 *              - we need not be this picky, but it doesn't hurt
 * S. Lawson - added TCP/UDP flag so we can pick unique ports and
 *             avoid reconnecting with a socket in TIME_WAIT (the
 *             original "oldport+510" scan needs a rewrite someday)
 */
static word findfreeport( word oldport, word proto_tcp )
{
    word temp;
    tcp_Socket *s;

// S. Lawson - s/b > 1     if (( oldport > 0 ) && (oldport < 0xffff))
    if (( oldport > 1 ) && (oldport < 0xffff))          // S. Lawson
        return( oldport );

// S. Lawson - start
//  if ( oldport == 0 ) oldport = 1025;
    if ( oldport == 0) {
       if (proto_tcp) {
          if ((oldport=next_tcp_port++)>=32767-510) next_tcp_port=1024;
       } else {
          if ((oldport=next_udp_port++)>=32767-510) next_udp_port=1024;
       }
    }
// S. Lawson - end
    else oldport = 513;

    for ( temp = oldport ; temp < oldport + 510 ; ++temp ) {
      if (!proto_tcp) {                         // S. Lawson
        if (( s = (tcp_Socket*)udp_allsocs) != NULL ) {
            while ( s->next && (s->myport != temp))
                s = (tcp_Socket*)s->next;
            if ( s->myport == temp ) continue;
        }
      } else {                                          // S. Lawson
        if ( (s = tcp_allsocs ) != NULL ) {
            while ( s->next && (s->myport != temp ))
                s = s->next;
            if ( s->myport == temp ) continue;
        }
      }                                                 // S. Lawson
      break;
    }
    return( temp );
}

/* socket, localport, destaddress */
int udp_open( udp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler )
{
    udp_close( s );
    largecheck( s, sizeof( udp_Socket ));
    memset( s, 0, sizeof( udp_Socket ));
    s->rdata = s->rddata;
    s->maxrdatalen = tcp_MaxBufSize;
    s->ip_type = UDP_PROTO;

    lport = findfreeport(lport, false);         // S. Lawson - added "false"

    s->myport = lport;
    s->myaddr = my_ip_addr;

    /* check for broadcast */
    if ( (long)(ina) == -1 )
        memset( &s->hisethaddr, 0xff, sizeof( eth_address ));
//  EE 2000.9.13
//  handle late binding IP
    else if ( ina == 0 )
//      Changed.  EE 2000.9.13 we want this zeroed so udp_writes will arp_resolve
//                once we have bound to a particular IP and
        memset( &s->hisethaddr, 0x00, sizeof( eth_address ));
    else if ( ! _arp_resolve(ina, &s->hisethaddr, 0) )
        return( 0 );

    s->hisaddr = ina;
    s->hisport = port;
    s->dataHandler = datahandler;
    s->usr_yield = system_yield;
    s->safetysig = SAFETYUDP;
    s->next = udp_allsocs;
    udp_allsocs = s;
    return( 1 );
}

/*
 * Actively open a TCP connection to a particular destination.
 *      - 0 on error

⌨️ 快捷键说明

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