📄 pctcp.c
字号:
/* 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 + -