home *** CD-ROM | disk | FTP | other *** search
- #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
- *
- */
- // Modifications to this file made by Shawn LaMaster and Jonathan Kent to
- // convert from (Borland) BCC to (Microsoft) MSC600 compiler. 1/13/92
- // - using large memory model.
- // - change <mem.h> to <memory.h>
-
- #include <time.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- // #include <mem.h>
- #include <memory.h>
- #include <dos.h>
-
- #include <copyright.h>
- #include "wattcp.h"
- #include "elib.h"
-
- /* statics */
- static void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len);
- void tcp_sendsoon(tcp_Socket *s );
- static void udp_handler(in_Header *ip);
- static void tcp_handler(in_Header *ip);
- static void tcp_send(tcp_Socket *s);
- static void tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp);
-
- static char far *mono = (char far *)0xb0000000L;
- static char far *colour = (char far *)0xb8000000L;
-
- static initialized = 0;
- static void (*system_yield)() = NULL;
- void (*_dbugxmit)() = NULL;
- void (*_dbugrecv)() = NULL;
-
- char *_hostname = "012345678901234567890123456789012345678901234567890";
-
- word _mss = ETH_MSS;
-
- char *_wattcp = WATTCP_C;
-
- /*
- * sock_yield - enable user defined yield function
- */
- sock_yield( tcp_Socket *s, void (*fn)())
- {
- if ( s )
- s->usr_yield = fn;
- else
- system_yield = fn;
- }
-
- /*
- * sock_mode - set binary or ascii - affects sock_gets, sock_dataready
- * - set udp checksums
- */
- sock_mode( sock_type *s, word mode )
- {
- 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( s , delayseconds )
- udp_Socket *s;
- int delayseconds;
- {
- if (delayseconds)
- s->usertimer = set_timeout( delayseconds );
- else
- s->usertimer = 0;
- }
-
- int ip_timer_expired( s )
- udp_Socket *s;
- {
- if (! s->usertimer) /* cannot expire */
- return( 0 );
- return( chk_timeout( s->usertimer));
- }
- longword MsecClock()
- {
- return( (*realclock) * 055L);
- }
- static long make_timeout( word timeout )
- {
- if ( timeout ) return( set_timeout( timeout ));
- return( 0 );
- }
- /*
- * check_timeout - test agains timeout clock - account for overflow
- */
- static int check_timeout( unsigned long timeout )
- {
- if (timeout) return( chk_timeout( timeout ));
- return( 0 );
- }
-
- /*
- * Local IP address
- */
- longword my_ip_addr = 0L; /* for external references */
- longword sin_mask = 0xfffffe00L;
- longword sin_gate = 0x0;
-
- #ifdef OLD
- ip_init( long ip, long mask, long gateway )
- {
- my_ip_addr = ip;
- sin_mask = mask;
- sin_gate = gateway;
- }
- #endif // OLD
-
- /*
- * 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 */
-
- word debug_on = 0;
-
- /*
- * Shut down the card and all services
- */
- tcp_shutdown()
- {
- while (tcp_allsocs)
- tcp_abort( tcp_allsocs );
- _eth_release();
- initialized = 0;
- }
-
- /*
- * tcp_Init - Initialize the tcp implementation
- * - may be called more than once without hurting
- */
- tcp_init()
- {
- extern int _arp_last_gateway;
- extern int _last_nameserver;
-
- if (!initialized) {
- /* initialize ethernet interface */
- initialized = 1;
- _eth_init();
-
- /* 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 */
-
- if (!my_ip_addr) {
- /* using our local reverse ethernet address thingamajig */
- memmove( &my_ip_addr, &_eth_addr[2], 4 );
- }
- _eth_free( 0 );
- next_udp_port = next_tcp_port = 1024 + ((*realclock >> 7 )& 0x1ff);
- }
- }
-
- /*
- * Checks for bugs in large model C compiler
- */
- static largecheck( void *s, int size )
- {
- if ( (word)(FP_OFF(s)) > (word)(-size)) {
- outs("ERROR: C compiler sock size error\n");
- exit( 3 );
- }
- }
-
- /* socket, localport, destaddress */
- int udp_open(s, lport, ina, port, datahandler)
- udp_Socket *s;
- longword ina;
- word lport, port;
- procref datahandler;
- {
- udp_close( s );
- largecheck( s, sizeof( udp_Socket ));
- memset( s, 0, sizeof( udp_Socket ));
- s->ip_type = UDP_PROTO;
- if ( lport == 0 ) lport = ++next_udp_port; /* get a nonzero port val */
- s->myport = lport;
-
- /* check for broadcast */
- if ( (long)(ina) == -1 || !ina )
- memset( s->hisethaddr, 0xff, sizeof( eth_address ));
- else if ( ! _arp_resolve(ina, &s->hisethaddr) )
- 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
- */
- int tcp_open(tcp_Socket *s, word lport, longword ina, word port, procref datahandler)
- {
- largecheck( s, sizeof( tcp_Socket )); /* stack space warnings */
- tcp_unthread(s); /* just in case not totally closed */
-
- memset( s, 0, sizeof( tcp_Socket));
- s->ip_type = TCP_PROTO;
- s->mss = _mss;
- s->state = tcp_StateSYNSENT;
- s->timeout = set_timeout( tcp_LONGTIMEOUT );
- s->rmaxdatalen = tcp_MaxBufSize;
- s->cwindow = s->wwindow = 1; /* slow start VJ algorithm */
- s->vj_sa = 4; /* about 250 ms */
- if ( lport == 0 ) lport = ++next_tcp_port; /* get a nonzero port val */
- s->myport = lport;
- if ( ! _arp_resolve(ina, &s->hisethaddr) )
- return( 0 );
-
- s->hisaddr = ina;
- s->hisport = port;
- s->seqnum = intel( set_timeout( 1 )) & 0xffff0000;
- s->datalen = 0;
- s->flags = tcp_FlagSYN;
- s->unhappy = true;
- s->dataHandler = datahandler;
- s->usr_yield = system_yield;
-
- s->safetysig = SAFETYTCP; /* insert into chain */
- s->next = tcp_allsocs;
- tcp_allsocs = s;
-
- s->rtt_delay = s->rtt_smooth = 18; /* one second startup */
- tcp_send(s);
- return( 1 );
- }
-
- /*
- * Passive open: listen for a connection on a particular port
- */
- tcp_listen(tcp_Socket *s, word lport, longword ina, word port, procref datahandler, word timeout)
- {
- largecheck( s, sizeof( tcp_Socket ));
- tcp_unthread(s); /* just in case not totally closed */
- memset( s, 0, sizeof( tcp_Socket));
- s->ip_type = TCP_PROTO;
- s->mss = _mss;
- s->rmaxdatalen = tcp_MaxBufSize;
- s->cwindow = s->wwindow = 1; /* slow start VJ algorithm */
- s->vj_sa = 36; /* about 250 ms */
-
- s->state = tcp_StateLISTEN;
- if ( !timeout ) s->timeout = 0; /* forever... */
- else s->timeout = set_timeout( timeout );
- s->myport = lport;
- s->hisport = port;
- s->hisaddr = ina;
- s->seqnum = intel( (word)(s));
- s->datalen = 0;
- s->flags = 0;
- s->unhappy = false;
- s->dataHandler = datahandler;
- s->usr_yield = system_yield;
-
- s->safetysig = SAFETYTCP; /* insert into chain */
- s->next = tcp_allsocs;
- tcp_allsocs = s;
-
- return( 1 );
- }
-
-
- static udp_close(ds)
- udp_Socket *ds;
- {
- udp_Socket *s, **sp;
-
- sp = &udp_allsocs;
- for (;;) {
- s = *sp;
- if ( s == ds ) {
- *sp = s->next;
- break;
- }
- if ( !s ) break;
- if ( ! s->err_msg ) s->err_msg = "UDP Close called";
- sp = &s->next;
- }
- }
-
- /*
- * Send a FIN on a particular port -- only works if it is open
- * Must still allow receives
- */
- static 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 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)
- s->err_msg = "Connection closed normally";
- s->state = tcp_StateFINWT1;
- s->timeout = set_timeout( 4 ); /* should be a pretty lengthy time */
- tcp_send( s );
- }
- s->unhappy = true;
- } else if (s->state == tcp_StateCLOSWT ) {
- /* need to ack the fin and get on with it */
- s->state = tcp_StateLASTACK;
- s->flags |= tcp_FlagFIN;
- tcp_send( s );
- s->unhappy = true;
- }
- }
-
- /*
- * Abort a tcp connection
- */
- static tcp_abort(tcp_Socket *s)
- {
- if (!s->err_msg) s->err_msg = "TCP_ABORT";
- if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
- s->flags = tcp_FlagRST | tcp_FlagACK ;
- s->unhappy = true;
- tcp_send(s);
- }
- s->unhappy = false;
- s->datalen = 0;
- s->state = tcp_StateCLOSED;
- /* if (s->dataHandler) s->dataHandler(s, 0, -1); */
- tcp_unthread(s);
- }
-
- void sock_abort(tcp_Socket *s )
- {
- if ( s->ip_type == TCP_PROTO )
- tcp_abort( s );
- else
- udp_close( s );
- }
- /*
- * tcp_sendsoon - schedule a transmission pretty soon
- * - this one has an imperfection at midnight, but it
- * is not significant to the connection performance
- */
- void tcp_sendsoon(tcp_Socket *s )
- {
- longword temp;
- if (s->ip_type == TCP_PROTO ) {
- temp = set_ttimeout( 1 );
- if ( temp == s->rtt_time && s->rto < 2 && s->recent == 0 ) {
- s->karn_count = 0;
- tcp_send( s );
- s->recent = 1;
- return;
- }
- if ((s->unhappy || s->datalen > 0 || s->karn_count == 1)
- && (s->rtt_time < temp ))
- return;
-
- s->rtt_time = temp;
- s->karn_count = 1;
- }
- }
-
- /*
- * Retransmitter - called periodically to perform tcp retransmissions
- */
- static longword retran_strat = 0L; /* timeout retran strategy */
- static void tcp_Retransmitter()
- {
- tcp_Socket *s;
-
- /* only do this once per RETRAN_STRAT_TIME milliseconds */
- if ( !chk_timeout( retran_strat ))
- return;
- retran_strat = set_ttimeout( RETRAN_STRAT_TIME );
-
- for ( s = tcp_allsocs; s; s = s->next ) {
- if ( s->datalen > 0 || s->unhappy || s->karn_count == 1 ) {
- /* retransmission strategy */
- if ( chk_timeout( s->rtt_time)) {
- if ( s->karn_count == 0 ) { /* if really did timeout */
- s->karn_count = 2;
- s->unacked = 0;
- }
- tcp_send(s);
- }
- }
- /* handle inactive tcp timeouts */
- if ( sock_inactive && s->inactive_to ) {
- if ( chk_timeout( s->inactive_to)) {
- /* this baby has timed out */
- s->err_msg = "Connection timed out - no activity";
- sock_close( s );
- }
- }
- if ( s->timeout && chk_timeout( s->timeout)) {
- if ( s->state == tcp_StateTIMEWT ) {
- s->state = tcp_StateCLOSED;
- tcp_unthread(s);
- break;
- } else if (s->state != tcp_StateESTAB && s->state != tcp_StateESTCL ) {
- s->err_msg = "Timeout, aborting";
- tcp_abort(s);
- break;
- }
- }
- }
- }
-
- /*
- * Unthread a socket from the tcp socket list, if it's there
- */
- static tcp_unthread(tcp_Socket *ds)
- {
- tcp_Socket *s, **sp;
-
- if (!ds->rdatalen || (ds->state > tcp_StateESTCL))
- ds->ip_type = 0; /* fail io */
- ds->state = tcp_StateCLOSED; /* tcp_tick needs this */
- sp = &tcp_allsocs;
- for (;;) {
- s = *sp;
- if ( s == ds ) {
- *sp = s->next;
- continue; /* unthread multiple copies if necessary */
- }
- if ( !s ) break;
- sp = &s->next;
- }
- }
-
- /*
- * tcp_tick - called periodically by user application
- * - returns 1 when our socket closes
- * - called with socket parameter or NULL
- */
- tcp_tick( sock_type *s )
- {
- in_Header *ip;
- static longword timeout = 0;
- static longword start = 0;
-
- int x;
- int packettype;
-
- /* finish off dead sockets */
- if ( s ) {
- if (( s->tcp.ip_type == TCP_PROTO ) &&
- ( s->tcp.state == tcp_StateCLOSED ) &&
- ( s->tcp.rdatalen == 0 )) {
- tcp_unthread((tcp_Socket *)s);
- s->tcp.ip_type = 0;
- }
- }
-
-
- /* plan our next retransmit */
-
- if ( !timeout )
- timeout = make_timeout( tcp_RETRANSMITTIME );
-
- while ( ip = (in_Header *)_eth_arrived( &packettype ) ) {
- start = *realclock;
-
- switch ( packettype ) {
- case /*0x800*/ 0x008 :
- /* do IP */
- if ( checksum(ip, in_GetHdrlenBytes(ip)) == 0xffff ) {
- if ( !my_ip_addr || (intel( ip->destination ) == my_ip_addr)){
- switch ( ip->proto ) {
- case TCP_PROTO :
- tcp_handler(ip);
- break;
- case UDP_PROTO :
- udp_handler(ip);
- break;
- case ICMP_PROTO :
- icmp_handler(ip);
- break;
- }
- }
- } else {
- if (debug_on)
- outs("IP Received BAD Checksum \n\r");
- }
- break;
- case /*0x806*/ 0x608 :
- /* do arp */
- _arp_handler(ip);
- break;
- }
- if (ip) _eth_free(ip);
-
- continue;
- }
- /*
- x = *realclock - start;
- timeout -= x;
- */
- /* check for our outstanding packets */
- tcp_Retransmitter();
-
- return( s->udp.ip_type );
- }
-
- tcp_set_debug_state( x )
- int x;
- {
- debug_on = x;
- }
-
- /* returns 1 if connection is established */
- int tcp_established(tcp_Socket *s)
- {
- return( s->state == tcp_StateESTAB || s->state == tcp_StateESTCL
- || s->state == tcp_StateCLOSWT );
- }
-
-
- static udp_Write(s, datap, len)
- udp_Socket *s;
- byte *datap;
- int len;
- {
- tcp_PseudoHeader ph;
- struct _pkt {
- in_Header in;
- udp_Header udp;
- int data;
- /* longword maxsegopt; */
- } *pkt;
- void *dp;
- in_Header *inp;
- udp_Header *udpp;
-
- pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr[0], /*0x800*/ 8);
- dp = &pkt->data;
- inp = &pkt->in;
- udpp = &pkt->udp;
-
- inp->length = intel16( sizeof(in_Header) + UDP_LENGTH + len );
-
- /* udp header */
- udpp->srcPort = intel16( s->myport );
- udpp->dstPort = intel16( s->hisport );
- udpp->checksum = 0;
- udpp->length = intel16( UDP_LENGTH + len );
- memmove( dp,datap, len );
-
- /* internet header */
- inp->ver = 4;
- inp->hdrlen = 5;
- inp->tos = 0;
- /* inp->vht = 0x4500;*/ /* version 4, hdrlen 5, tos 0 */
- inp->identification = intel16( ++ip_id ); /* was post inc */
- inp->frag = 0;
- inp->ttl = 254;
- inp->proto = UDP_PROTO; /* udp */
- /* inp->ttlProtocol = (250<<8) + 6; */
- inp->checksum = 0;
- inp->source = intel( my_ip_addr );
- inp->destination = intel( s->hisaddr );
- inp->checksum = ~checksum( inp, sizeof(in_Header))/* 0*/; /* Watstar */
-
-
- /* compute udp checksum if desired */
- if ( s->sock_mode & UDP_MODE_NOCHK )
- udpp->checksum = 0;
- else {
- ph.src = inp->source; /* already INTELled */
- ph.dst = inp->destination;
- ph.mbz = 0;
- ph.protocol = UDP_PROTO; /* udp */
- ph.length = udpp->length; /* already INTELled */
-
- ph.checksum = checksum(&pkt->udp, intel16(ph.length));
- udpp->checksum = ~checksum(&ph, sizeof(ph));
- }
-
- if (_dbugxmit) (*_dbugxmit)(s,inp,udpp);
- _eth_send( intel16( inp->length ));
-
- return ( len );
- }
-
- /*
- * udp_read - read data from buffer, does large buffering
- */
- static int udp_read(s, datap, maxlen)
- udp_Socket *s;
- byte *datap;
- int maxlen;
- {
- int x;
-
- if (( x = s->rdatalen ) > 0) {
- if ( x > maxlen ) x = maxlen;
- if ( x > 0 ) {
- memmove( datap, s->rdata, x );
- if ( s->rdatalen -= x )
- memmove( s->rdata, s->rdata + x, s->rdatalen);
- }
- }
- return( x );
- }
-
- _udp_cancel( in_Header *ip )
- {
- int len;
- udp_Header *up;
- udp_Socket *s;
-
- /* match to a udp socket */
- len = in_GetHdrlenBytes(ip);
- up = (udp_Header *)((byte *)ip + len); /* udp frame pointer */
-
- /* demux to active sockets */
- for ( s = udp_allsocs; s; s = s->next )
- if ( s->hisport != 0 &&
- intel16( up->dstPort ) == s->myport &&
- intel16( up->srcPort ) == s->hisport &&
- intel( ip->source ) == s->hisaddr ) break;
- if ( !s ) {
- /* demux to passive sockets */
- for ( s = udp_allsocs; s; s = s->next )
- if ( s->hisport == 0 && intel16( up->dstPort ) == s->myport ) break;
- }
- if (s) {
- s->rdatalen = 0;
- s->ip_type = 0;
- }
- }
-
- _tcp_cancel(in_Header *ip)
- {
- int len;
- tcp_Socket *s;
- tcp_Header *tp;
-
- len = in_GetHdrlenBytes(ip); /* check work */
-
- tp = (tcp_Header *)((byte *)ip + len); /* tcp frame pointer */
-
- /* demux to active sockets */
- for ( s = tcp_allsocs; s; s = s->next ) {
- if ( s->hisport != 0 &&
- intel16( tp->dstPort ) == s->myport &&
- intel16( tp->srcPort ) == s->hisport &&
- intel( ip->source ) == s->hisaddr ) {
- s->err_msg = "ICMP closed connection";
- s->rdatalen = s->datalen = 0;
- s->state = tcp_StateCLOSED;
- /* if (s->dataHandler) s->dataHandler(s, 0, -1); */
- }
- }
- }
-
- static int tcp_read(tcp_Socket *s, byte *datap, int maxlen)
- {
- int x;
-
- if (( x = s->rdatalen) > 0) {
- if ( x > maxlen ) x = maxlen;
- if ( x > 0 ) {
- memmove( datap, s->rdata, x );
- if (( s->rdatalen -= x ) > 0 ) {
- memmove( s->rdata, s->rdata + x, s->rdatalen );
- tcp_sendsoon( s ); /* update the window */
- } else
- tcp_send( s ); /* update window el-pronto */
- }
- } else if ( s->state == tcp_StateCLOSWT )
- tcp_close( s );
- return( x );
- }
-
- /*
- * Write data to a connection.
- * Returns number of bytes written, == 0 when connection is not in
- * established state.
- */
- static tcp_Write(tcp_Socket *s, byte *dp, int len)
- {
- int x;
-
- /* no longer uses tcp_MaxData */
- if ( s->state != tcp_StateESTAB ) len = 0;
- if ( len > (x = tcp_MaxBufSize - s->datalen) ) len = x;
- if ( len > 0 ) {
- memmove( s->data + s->datalen, dp, len );
-
- s->datalen += len;
- s->unhappy = true; /* redundant because we have outstanding data */
-
- if ( s->sock_mode & TCP_MODE_NONAGLE ) {
- 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->mss)/2 ))
- tcp_send( s );
- else
- tcp_sendsoon( s );
- }
- }
-
- return ( len );
- }
-
- /*
- * Send pending data
- */
- static tcp_Flush(tcp_Socket *s)
- {
- if ( s->datalen > 0 ) {
- s->flags |= tcp_FlagPUSH;
- tcp_send(s);
- }
- }
-
- /*
- * Handler for incoming packets.
- */
- static void udp_handler(in_Header *ip)
- {
- udp_Header *up;
- tcp_PseudoHeader ph;
- word len;
- byte *dp;
- udp_Socket *s;
-
-
- len = in_GetHdrlenBytes(ip);
- up = (udp_Header *)((byte *)ip + len); /* udp segment pointer */
- len = intel16( up->length );
-
- /* demux to active sockets */
- for ( s = udp_allsocs; s; s = s->next ) {
- if ( s->safetysig != SAFETYUDP ) {
- if (debug_on) outs("chain error in udp\r\n");
- }
- if ( s->hisport != 0 &&
- intel16( up->dstPort ) == s->myport &&
- intel16( up->srcPort ) == s->hisport &&
- intel( ip->source ) == s->hisaddr ) break;
- }
- if (_dbugrecv) (*_dbugrecv)(s,ip,up);
- if ( !s ) {
- /* demux to passive sockets */
- for ( s = udp_allsocs; s; s = s->next )
- if ( s->hisaddr == 0 && intel16( up->dstPort ) == s->myport ) {
- if (_arp_resolve(intel(ip->source), &s->hisethaddr)) {
- s->hisaddr = intel( ip->source );
- s->hisport = intel16( up->srcPort );
- }
- break;
- }
- }
- if ( !s ) {
- /* demux to broadcast sockets */
- for ( s = udp_allsocs; s; s = s->next )
- if ( s->hisaddr == 0xffffffff && intel16( up->dstPort ) == s->myport ) break;
- }
-
- if ( !s ) {
- if (debug_on) outs("discarding...");
- return;
- }
-
- if ( up->checksum ) {
- ph.src = ip->source; /* already INTELled */
- ph.dst = ip->destination;
- ph.mbz = 0;
- ph.protocol = UDP_PROTO;
- ph.length = up->length;
- ph.checksum = checksum(up, len);
- if (checksum(&ph, sizeof( tcp_PseudoHeader)) != 0xffff)
- return;
- }
-
- /* process user data */
- if ( (len -= UDP_LENGTH ) > 0) {
- dp = (byte *)( up );
- if (s->dataHandler) s->dataHandler( s, &dp[ UDP_LENGTH ], len , &ph);
- else {
- if (len > tcp_MaxBufSize ) len = tcp_MaxBufSize;
- memmove( s->rdata, &dp[ UDP_LENGTH ], len );
- s->rdatalen = len;
- }
- }
- }
-
- static void tcp_handler(in_Header *ip)
- {
- tcp_Header *tp;
- tcp_PseudoHeader ph;
- int len;
- byte *dp;
- int diff;
- tcp_Socket *s;
- word flags;
- long diffticks, ldiff; /* must be signed */
-
-
-
- len = in_GetHdrlenBytes(ip);
- len = intel16( ip->length ) - len; /* len of tcp data */
-
- len = in_GetHdrlenBytes(ip);
- tp = (tcp_Header *)((byte *)ip + len); /* tcp frame pointer */
- len = intel16( ip->length ) - len; /* len of tcp data */
- flags = intel16( tp->flags );
-
- if (debug_on > 1) {
- mono[160]++;
- colour[160]++;
- mono[162] = colour[162] = (flags & tcp_FlagSYN) ? 'S' : ' ';
- mono[164] = colour[164] = (flags & tcp_FlagACK) ? 'A' : ' ';
- mono[166] = colour[166] = (flags & tcp_FlagFIN) ? 'F' : ' ';
- mono[168] = colour[168] = (flags & tcp_FlagRST) ? 'R' : ' ';
- }
-
-
- /* demux to active sockets */
- for ( s = tcp_allsocs; s; s = s->next ) {
- if ( s->safetysig != SAFETYTCP ) {
- if (debug_on) outs("chain error in tcp\r\n");
- }
- if ( s->hisport != 0 &&
- intel16( tp->dstPort ) == s->myport &&
- intel16( tp->srcPort ) == s->hisport &&
- intel( ip->source ) == s->hisaddr ) break;
- }
- if ( !s && (flags & tcp_FlagSYN)) {
- /* demux to passive sockets, must be a new session */
- for ( s = tcp_allsocs; s; s = s->next )
- if ((s->hisport == 0) && (intel16( tp->dstPort ) == s->myport ))
- break;
- }
-
-
- if (_dbugrecv) (*_dbugrecv)(s,ip,tp);
- if ( !s ) {
- if (!(flags & tcp_FlagRST)) tcp_rst( ip, tp );
- return;
- }
-
-
- /* save his ethernet address */
- memmove( &s->hisethaddr[0],&((((eth_Header *)ip) - 1)->source[0]), sizeof(eth_address));
-
- ph.src = ip->source; /* already INTELled */
- ph.dst = ip->destination;
- ph.mbz = 0;
- ph.protocol = TCP_PROTO;
- ph.length = intel16( len );
- ph.checksum = checksum(tp, len);
- if ( checksum(&ph, sizeof(ph)) != 0xffff ) {
- if (debug_on) outs("bad tcp checksum \n\r");
-
- /* tester */
- ph.checksum = checksum(tp, len);
- checksum(&ph, sizeof(ph));
-
- tcp_sendsoon( s );
- return;
- }
-
- /* reset code */
- if ( flags & tcp_FlagRST ) {
- if (debug_on) outs("\7\7\7\7\7\7\7connection reset\n");
- s->rdatalen = s->datalen = 0;
- s->err_msg = "Remote reset connection";
- s->state = tcp_StateCLOSED;
- /* if (s->dataHandler) s->dataHandler(s, 0, -1); */
- tcp_unthread(s);
- return;
- }
-
- if ( sock_inactive )
- s->inactive_to = set_timeout( sock_inactive );
-
-
- /* update our retransmission stuff */
- /* new algorithms */
- if (s->karn_count == 2) {
- s->unacked = 0;
- /* use the backed off rto - implied, no code necessary */
- /* reduce the transmit window */
- s->cwindow = 1;
- s->wwindow >>= 1;
- s->karn_count = 0;
- if (debug_on > 1 ) outs("wwindow zapped\n\r");
- } else {
- if ( s->vj_last ) {
- /* unnecessary to use unhappy || s->datalen ) */
- if ((diffticks = set_ttimeout( 0 ) - s->vj_last) >= 0 ) {
- /* we ignore the overnight case */
- diffticks -= (longword)( s->vj_sa >> 3 );
- s->vj_sa += (int)diffticks;
- if (diffticks < 0)
- diffticks = - diffticks;
- diffticks -= (s->vj_sd >> 2);
- s->vj_sd += (int)diffticks;
- if (s->vj_sa > MAXVJSA) s->vj_sa = MAXVJSA;
- if (s->vj_sd > MAXVJSD) s->vj_sd = MAXVJSD;
- }
- /* only recompute rtt hence rto after success */
- s->rto = 1 + ((s->vj_sa >> 2) + (s->vj_sd)) >> 1 ;
- }
- s->karn_count = 0;
- s->cwindow = 1 + ((s->wwindow++)>> 2);
- }
-
-
- switch ( s->state ) {
-
- case tcp_StateLISTEN: /* accepting SYNs */
- if ( flags & tcp_FlagSYN ) {
- s->acknum = intel( tp->seqnum ) + 1;
- s->hisport = intel16( tp->srcPort );
- s->hisaddr = intel( ip->source );
- s->flags = tcp_FlagSYN | tcp_FlagACK;
- s->state = tcp_StateSYNREC;
- s->unhappy = true;
- tcp_send(s); /* we must respond immediately */
-
- s->timeout = set_timeout( tcp_TIMEOUT );
- } else
- tcp_rst( ip , tp ); /* send a reset */
-
- return;//( 1 );
- break; /* unreachable */
-
- case tcp_StateSYNSENT: /* added ACK Section */
- if ( flags & tcp_FlagSYN ) {
- s->flags = tcp_FlagACK;
- s->timeout = set_timeout( tcp_TIMEOUT );
-
- /* FlagACK means connection established, else SYNREC */
- if ( flags & tcp_FlagACK) {
- /* but is it for the correct session ? */
- if (tp->acknum == intel(s->seqnum + 1)) {
- s->state = tcp_StateESTAB;
- s->seqnum++; /* good increment */
- s->acknum = intel( tp->seqnum ) + 1; /* 32 bits */
- tcp_ProcessData(s, tp, len); /* someone may try it */
- s->unhappy = true; /* they must be told */
- } else {
- /* wrong ack, force a RST and resend SYN soon*/
- s->flags = tcp_FlagRST;
- s->unhappy = true;
- tcp_send( s );
- s->flags = tcp_FlagSYN;
- tcp_send( s );
- }
- } else {
- s->acknum++;
- s->state = tcp_StateSYNREC;
- #ifdef unnecessary
- tcp_send( s ); /* send immediately */
- s->unhappy = true;
- #endif // unnecessary
- return;//( 1 );
- }
- } else
- tcp_rst( ip, tp );
- break;
-
- case tcp_StateSYNREC: /* recSYNSENT, sentACK, waiting EST */
- if ( flags & tcp_FlagSYN ) {
- s->flags = tcp_FlagSYN | tcp_FlagACK;
- s->unhappy = true;
- tcp_send(s);
- s->timeout = set_timeout( tcp_TIMEOUT );
- return;//( 1 );
- }
- if ( (flags & tcp_FlagACK) && (intel( tp->acknum ) == (s->seqnum + 1))) {
- s->window = intel16( tp->window );
- s->flags = tcp_FlagACK;
- s->state = tcp_StateESTAB;
- s->seqnum++;
- s->timeout = 0; /* never timeout */
- s->unhappy = false;
- return;//( 1 );
- }
-
- break;
- case tcp_StateESTAB:
- case tcp_StateESTCL:
- case tcp_StateCLOSWT:
-
- if ( !(flags & tcp_FlagACK)) return; /* must ack somthing */
- if ( flags & tcp_FlagSYN ) {
- tcp_rst( ip , tp );
- return;
- }
- s->timeout = 0l; /* we do not timeout at this point */
-
- /* process ack value in packet - but only if it falls
- * within current window */
-
- ldiff = intel( tp->acknum ) - s->seqnum;
- diff = (int) ldiff;
-
- if ( ldiff >= 0 && diff <= s->datalen ) {
- s->datalen -= diff;
- s->unacked -= diff;
- if (s->datalen < 0) s->datalen = 0; /* remote proto error */
- if ( s->queuelen ) {
- s->queue += diff;
- s->queuelen -= diff;
- } else
- memmove( s->data,s->data + diff, s->datalen );
- s->seqnum += ldiff;
- } else
- s->unacked = 0;
- if (s->unacked < 0) s->unacked = 0;
-
- s->flags = tcp_FlagACK;
- tcp_ProcessData(s, tp, len);
-
- if (( flags & tcp_FlagFIN ) && (s->state != tcp_StateCLOSWT )
- && ( s->acknum == intel( tp->seqnum ))) {
- s->acknum ++;
- s->err_msg = "Connection closed";
- s->state = tcp_StateCLOSWT;
- tcp_send( s );
- s->state = tcp_StateLASTACK;
- s->flags |= tcp_FlagFIN;
- s->unhappy = true;
- }
-
- if ( diff || len ) {
- /* need to update window, but how urgent ??? */
- if ( s->unacked > s->rmaxdatalen / 2 )
- tcp_send( s );
- else
- tcp_sendsoon( s );
- }
- if ( s->state == tcp_StateESTCL )
- tcp_close( s );
- return;//( 1 );
- break; /* dummy for compiler */
-
- case tcp_StateFINWT1:
- /* They have not necessarily read all the data yet, we must
- still supply it as requested */
-
- ldiff = intel( tp->acknum ) - s->seqnum;
- diff = (int) ldiff;
- if ( ldiff >= 0 && diff <= s->datalen ) {
- s->datalen -= diff;
- s->unacked -= diff;
- if (s->datalen < 0) s->datalen = 0;
- if ( s->queuelen ) {
- s->queue += diff;
- s->queuelen -= diff;
- } else
- memmove( s->data,s->data + diff, s->datalen );
- s->seqnum += ldiff;
- if (ldiff == 0 || s->unacked < 0) s->unacked = 0;
-
- }
-
- /* they may still be transmitting data, we must read it */
-
- tcp_ProcessData(s, tp, len);
-
- /* check if other tcp has acked all sent data and is ready
- to change states */
-
- if ( flags & (tcp_FlagFIN|tcp_FlagACK) == tcp_FlagFIN|tcp_FlagACK) {
- /* trying to do similtaneous close */
- if (( intel( tp->acknum ) >= s->seqnum + 1 ) &&
- ( intel( tp->seqnum) == s->acknum )) {
- s->seqnum++;
- s->acknum++;
- s->flags = tcp_FlagACK;
- tcp_send( s );
- s->unhappy = false;
- s->timeout = set_timeout( 2 );
- s->state = tcp_StateCLOSED;
- }
- } else if ( flags & tcp_FlagACK ) {
- /* other side is legitimately acking our fin */
- if (( intel( tp->acknum ) == s->seqnum + 1 ) &&
- ( intel( tp->seqnum ) == s->acknum ) &&
- ( s->datalen == 0 )) {
- s->seqnum++;
- s->acknum++;
- s->state = tcp_StateFINWT2;
- s->timeout = set_timeout( 3 );
- s->unhappy = false; /* we don't send anything */
- }
- }
- break;
-
- case tcp_StateFINWT2:
- if ((flags & (tcp_FlagACK | tcp_FlagFIN)) ==
- tcp_FlagACK | tcp_FlagFIN) {
- if (( intel( tp->acknum ) == s->seqnum ) &&
- ( intel( tp->seqnum ) == s->acknum )) {
- s->acknum++;
- s->flags = tcp_FlagACK;
- tcp_send( s );
- s->unhappy = false; /* we don't send anything */
- s->timeout = set_timeout( 2 );
- s->state = tcp_StateCLOSED;
- return;//( 1 );
- }
- }
- break;
-
- case tcp_StateCLOSING:
- if ((flags & (tcp_FlagACK | tcp_FlagFIN)) == tcp_FlagACK ) {
- if (( tp->acknum == intel(s->seqnum) ) &&
- ( tp->seqnum == intel(s->acknum))) {
- s->state = tcp_StateTIMEWT;
- s->timeout = set_timeout( tcp_TIMEOUT );
- s->unhappy = false;
- }
- }
- break;
-
- case tcp_StateLASTACK:
- if ( flags & tcp_FlagFIN ) {
- /* they lost our two packets, back up */
- s->flags = tcp_FlagACK;
- /* JOE tcp_send( s ); */
- s->flags = tcp_FlagACK | tcp_FlagFIN;
- tcp_send( s );
- s->unhappy = TRUE; /* FALSE; */
- return;//( 1 );
- } else {
- if (( intel( tp->acknum ) == (s->seqnum + 1 )) &&
- ( intel( tp->seqnum ) == s->acknum )) {
- s->state = tcp_StateCLOSED; /* no 2msl necessary */
- s->unhappy = false; /* we're done */
- return;//( 1 );
- }
- }
- break;
-
- case tcp_StateTIMEWT:
- if ( flags & (tcp_FlagACK | tcp_FlagFIN) == tcp_FlagACK | tcp_FlagFIN) {
- /* he needs an ack */
- s->flags = tcp_FlagACK;
- tcp_send( s );
- s->unhappy = false;
- s->state = tcp_StateCLOSED; /* support 2 msl in rst code */
- }
- break;
- }
- if (s->unhappy) tcp_sendsoon(s);
- }
-
- /*
- * Process the data in an incoming packet.
- * Called from all states where incoming data can be received: established,
- * fin-wait-1, fin-wait-2
- */
- static void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len)
- {
- long ldiff;
- int diff, x;
- word flags;
- byte *dp;
-
- word *options, numoptions, opt_temp;
-
- s->window = intel16( tp->window );
-
- flags = intel16( tp->flags );
- ldiff = s->acknum - intel( tp->seqnum );
-
- if ( flags & tcp_FlagSYN ) ldiff--; /* back up to 0 */
- diff = (int) ldiff;
-
- /* find the data portion */
- x = tcp_GetDataOffset(tp) << 2; /* quadword to byte format */
- dp = (byte *)tp + x;
-
- /* process those options */
- if ( numoptions = x - sizeof( tcp_Header )) {
- options = (word*)((byte *)(tp) + sizeof( tcp_Header));
- while ( numoptions-- > 0 ) {
- switch ( *options++ ) {
- case 0 : numoptions = 0; /* end of options */
- break;
- case 1 : break; /* nop */
-
- /* we are very liberal on MSS stuff */
- case 2 : if (*options == 2) {
- opt_temp = intel16( *(word*)(&options[1]));
- if (opt_temp < s->mss )
- s->mss = opt_temp;
- }
- numoptions -= 2 + *options;
- options += *options;
- break;
- }
- }
- }
- /* done option processing */
-
- len -= x; /* remove the header length */
- if ( ldiff >= 0 ) { /* skip already received bytes */
- dp += diff;
- len -= diff;
-
- if (s->dataHandler) {
- s->acknum += s->dataHandler(s, dp, len);
- } else {
- /* no handler, just dump to buffer, should be indexed, handles goofs */
- /* limit receive size to our window */
- if ( s->rdatalen >= 0 ) {
- if ( len > ( x = tcp_MaxBufSize - s->rdatalen ))
- len = x;
- if ( len > 0 ) {
- s->acknum += len; /* our new ack begins at end of data */
- memmove( &s->rdata[ s->rdatalen ],dp, len );
- s->rdatalen += len;
- }
- }
- }
- s->unhappy = (s->datalen) ? true : false;
- } else {
- tcp_sendsoon( s );
- return;
- }
-
- s->timeout = set_timeout( tcp_TIMEOUT );
- return;
- }
-
- /*
- * Format and send an outgoing segment
- */
- static void tcp_send(tcp_Socket *s)
- {
- tcp_PseudoHeader ph;
- struct _pkt {
- in_Header in;
- tcp_Header tcp;
- word maxsegopt[2];
- } *pkt;
- byte *dp;
- in_Header *inp;
- tcp_Header *tcpp;
- int senddatalen, sendtotlen, sendpktlen, startdata, sendtotdata;
-
- int ippkt; /* 1..s->cwindow */
-
- s->recent = 0;
- pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr[0], /*0x800*/ 8);
- dp = (byte *)&pkt->maxsegopt; /* dp constant for multi-packet sends */
- inp = &pkt->in;
- tcpp = &pkt->tcp;
-
-
- /* this is our total possible send size */
- if ( s->karn_count < 2 ) {
- sendtotdata = min( s->datalen - s->unacked, s->window -1 );
- startdata = s->unacked;
- } else {
- sendtotdata = (s->datalen >= s->window)? s->window-1 : s->datalen;
- startdata = 0;
- }
- sendtotlen = 0; /* running count of what we've sent */
-
- /* step through our packets */
- for ( ippkt = 1; ippkt <= s->cwindow; ++ippkt ) {
- /* adjust size for each packet */
- senddatalen = min( sendtotdata, s->mss );
-
- /*
- sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
- inp->length = intel16( sendpktlen );
- */
- /* tcp header */
- tcpp->srcPort = intel16( s->myport );
- tcpp->dstPort = intel16( s->hisport );
- tcpp->seqnum = intel( s->seqnum + startdata ); /* unacked - no longer sendtotlen */
- tcpp->acknum = intel( s->acknum );
-
- tcpp->window = intel16( s->rmaxdatalen - s->rdatalen );
- tcpp->flags = intel16( s->flags | 0x5000 );
- tcpp->checksum = 0;
- tcpp->urgentPointer = 0;
-
- /* do options if this is our first packet */
- if ((s->flags & (tcp_FlagSYN | tcp_FlagACK)) == tcp_FlagSYN) {
- sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header ) + 4;
- tcpp->flags = intel16( intel16( tcpp->flags) + 0x1000 );
- pkt->maxsegopt[0] = 0x0402;
- pkt->maxsegopt[1] = intel16( s->mss );
- dp += 4;
- } else {
- /* handle packets with data */
- if (senddatalen > 0) {
- sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
-
- /* get data from appropriate place */
- if (s->queuelen) memmove( dp,s->queue + startdata, senddatalen );
- else memmove( dp,s->data + startdata, senddatalen);
- } else {
- /* handle no-data, not-first-SYN packets */
- sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header );
- }
- }
-
- /* internet header */
- inp->ver = 4;
- inp->hdrlen = 5;
- inp->tos = 0;
- inp->identification = intel16( ++ip_id ); /* was post inc */
- inp->frag = 0;
- inp->ttl = 254;
- inp->proto = TCP_PROTO;
- inp->checksum = 0;
- inp->source = intel( my_ip_addr );
- inp->destination = intel( s->hisaddr );
- inp->length = intel16( sendpktlen );
-
- inp->checksum = ~checksum( inp, sizeof(in_Header));
-
- /* compute tcp checksum */
- ph.src = inp->source; /* already INTELled */
- ph.dst = inp->destination;
- ph.mbz = 0;
- ph.protocol = 6;
- ph.length = intel16( sendpktlen - sizeof(in_Header));
-
- ph.checksum = checksum(&pkt->tcp, (sendpktlen - sizeof(in_Header) +1) & 0xfffe);
-
- tcpp->checksum = ~checksum(&ph, sizeof(ph));
-
- if (_dbugxmit) (*_dbugxmit)(s,inp,tcpp);
- if (debug_on > 1) {
- mono[0]++;
- colour[0]++;
- mono[2] = colour[2] = (s->flags & tcp_FlagSYN) ? 'S' : ' ';
- mono[4] = colour[4] = (s->flags & tcp_FlagACK) ? 'A' : ' ';
- mono[6] = colour[6] = (s->flags & tcp_FlagFIN) ? 'F' : ' ';
- mono[8] = colour[8] = (s->flags & tcp_FlagRST) ? 'R' : ' ';
- }
- if ( _eth_send( intel16( inp->length ))) { /* encounterred error */
- tcp_sendsoon( s );
- return;
- }
-
- /* do next ip pkt */
- sendtotlen += senddatalen;
- startdata += senddatalen;
- sendtotdata -= senddatalen;
- if (sendtotdata <= 0 ) break;
- }
- s->vj_last = 0;
- if ( s->karn_count == 2 ) {
- if (s->rto) s->rto = (s->rto * 3) / 2;
- else s->rto = 4;
- } else {
- /* vj_last nonzero if we expect an immediate response */
- if (s->unhappy || s->datalen)
- s->vj_last = set_ttimeout( 0 );
- s->karn_count = 0;
- }
- s->rtt_time = set_ttimeout( s->rto + 2 );
- }
- /*
- * Format and send a reset tcp packet
- */
- static void tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp)
- {
- tcp_PseudoHeader ph;
- struct _pkt {
- in_Header in;
- tcp_Header tcp;
- word maxsegopt[2];
- } *pkt, *his_pkt;
-
- static longword nextrst = 0L;
- // byte *dp;
- word oldflags;
- in_Header *inp;
- tcp_Header *tcpp;
- eth_Header *eth;
- int sendtotlen; /* length of packet */
- longword templong;
-
- /* see RFC 793 page 65 for details */
-
- if ( !chk_timeout( nextrst )) return;
- nextrst = set_ttimeout( 1 );
-
- oldflags = intel16( oldtcpp->flags );
- if (oldflags & tcp_FlagRST ) return;//( 0 );
- #ifdef buggy
- if ( oldflags & tcp_FlagSYN )
- /* leave them */;
- else if ((oldflags & tcp_FlagACK) == 0) {
- oldtcpp->seqnum = 0;
- oldtcpp->flags = intel16( tcp_FlagACK );
- } else
- oldtcpp->flags = 0;
- #else
- /* believe this is better */
- if ( (oldflags & (tcp_FlagACK | tcp_FlagFIN)) == (tcp_FlagACK | tcp_FlagFIN) ){
- templong = oldtcpp->seqnum;
- oldtcpp->seqnum = oldtcpp->acknum;
- oldtcpp->acknum = templong;
- oldflags = tcp_FlagACK;
- } else if ((oldflags & (tcp_FlagSYN | tcp_FlagACK)) == tcp_FlagSYN ) {
- oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + 1 );
- oldtcpp->seqnum = 0;
- oldflags = tcp_FlagACK | tcp_FlagRST;
- } else if ( oldflags & tcp_FlagACK ) {
- oldtcpp->seqnum = oldtcpp->acknum;
- oldtcpp->acknum = 0;
- } else {
- oldtcpp->acknum = intel( intel(oldtcpp->seqnum) + 1);
- oldtcpp->seqnum = 0;
- }
- if ( oldflags & ( tcp_FlagFIN | tcp_FlagSYN ) == 0 )
- oldflags ^= tcp_FlagACK | tcp_FlagRST;
-
- #endif // buggy
- his_pkt = (struct _pkt*)( his_ip );
-
- /* convoluted mechanism - reads his ethernet address or garbage */
- eth = _eth_hardware( (byte*)his_ip );
-
- pkt = (struct _pkt *)_eth_formatpacket( eth, 8);
- // dp = &pkt->maxsegopt;
- inp = &pkt->in;
- tcpp = &pkt->tcp;
-
- sendtotlen = sizeof( tcp_Header ) + sizeof( in_Header );
- inp->length = intel16( sendtotlen );
-
- /* tcp header */
- tcpp->srcPort = oldtcpp->dstPort;
- tcpp->dstPort = oldtcpp->srcPort;
- tcpp->seqnum = oldtcpp->seqnum;
- tcpp->acknum = oldtcpp->acknum;
- tcpp->window = 0;
- tcpp->flags = intel16( oldflags );
- tcpp->checksum = 0;
- tcpp->urgentPointer = 0;
-
- /* internet header */
- inp->ver = 4;
- inp->hdrlen = 5;
- inp->tos = 0;
- inp->identification = intel16( ++ip_id );
- inp->frag = 0;
- inp->ttl = 254;
- inp->proto = TCP_PROTO;
- inp->checksum = 0;
- inp->source = his_ip->destination;
- inp->destination = his_ip->source;
-
- inp->checksum = ~checksum( inp, sizeof(in_Header))/* 0*/; /* Watstar */
-
- /* compute tcp checksum */
- ph.src = inp->source; /* already INTELled */
- ph.dst = inp->destination;
- ph.mbz = 0;
- ph.protocol = 6;
- ph.length = intel16( sendtotlen - sizeof(in_Header));
-
- ph.checksum = checksum(&pkt->tcp, (sendtotlen - sizeof(in_Header) +1) & 0xfffe);
- /* intel16(ph.length));*/ /* 0; *//* watstar */
- tcpp->checksum = ~checksum(&ph, sizeof(ph));
-
- if (_dbugxmit) (*_dbugxmit)(NULL,inp,tcpp);
- _eth_send( intel16( inp->length ));
- }
-
-
-
-
- /**********************************************************************
- * socket functions
- **********************************************************************/
-
- /* socket based stuff */
-
- /*
- * sock_read - read a socket with maximum n bytes
- * - busywaits until buffer is full but calls s->usr_yield
- * - returns count also when connection gets closed
- */
- sock_read(sock_type *s, byte *dp, int len )
- {
- int templen, count;
- count = 0;
- do {
- if ( s->udp.ip_type == UDP_PROTO )
- templen = udp_read( s, dp, len );
- else
- templen = tcp_read( (tcp_Socket *)s, dp, len);
- if (s->tcp.usr_yield) (s->tcp.usr_yield)();
- if (templen < 1 ) {
- if (!tcp_tick( s )) return( count );
- } else {
- count += templen;
- dp += templen;
- len -= templen;
- }
- } while ( len );
- return( count );
- }
- /*
- * sock_fead - read a socket with maximum n bytes
- * - does not busywait until buffer is full
- */
- sock_fastread(sock_type *s, byte *dp, int len )
- {
- if ( s->udp.ip_type == UDP_PROTO )
- len = udp_read( s, dp, len );
- else
- len = tcp_read( (tcp_Socket *)s, dp, len);
- return( len );
- }
-
-
- /*
- * sock_write - writes data and returns length written
- * - does not perform flush
- * - repeatedly calls s->usr_yield
- */
-
- sock_write(sock_type *s, byte *dp, int len)
- {
- int offset, oldlen, oldmode, proto;
-
- oldlen = len;
- offset = 0;
-
- proto = (s->udp.ip_type == TCP_PROTO);
- if ( proto ) oldmode = s->tcp.flags & tcp_FlagPUSH;
- while ( len > 0) {
- if (proto) {
- s->tcp.flags |= oldmode;
- offset += tcp_Write( (tcp_Socket *)s, &dp[ offset ], len);
- } else
- offset += udp_Write( s, &dp[ offset ], len );
- len = oldlen - offset;
- if (s->udp.usr_yield)(s->udp.usr_yield)();
- if (!tcp_tick(s)) return( 0 );
- }
- return( oldlen );
- }
-
-
-
- sock_fastwrite(sock_type *s, byte *dp, int len)
- {
- return( ( s->udp.ip_type == UDP_PROTO ) ?
- udp_Write( s, dp, len ) :
- tcp_Write( (tcp_Socket *)s, dp, len) );
- }
-
- void sock_enqueue(sock_type *s, byte *dp, int len)
- {
- int written;
- if ( s->udp.ip_type == UDP_PROTO ) {
- do {
- written = udp_Write( s, dp, len );
- dp += written;
- } while (len -= written > 0);
- } else {
- s->tcp.queue = dp;
- s->tcp.queuelen = len;
- s->tcp.datalen = len;
- tcp_send( (tcp_Socket *)s ); /* start sending it */
- }
- }
-
-
- sock_flush( sock_type *s )
- {
- if ( s->tcp.ip_type == TCP_PROTO )
- tcp_Flush( (tcp_Socket *)s );
- }
-
- #ifdef DISCARD
- sock_waitwrite( sock_type *s, byte *dp, int len )
- {
- int templen;
- if ( s->udp.ip_type == UDP_PROTO ) udp_Write( s,dp,len);
- else if ( (templen = s->tcp.datalen) + len > s->tcp.mss / 2 )
- return( tcp_Write( s, dp, len ) - templen );
- else {
- memmove( &s->tcp.data[s->tcp.datalen], dp, len );
- s->tcp.datalen += len;
- return( len );
- }
- }
- #endif // DISCARD
- /*
- * sock_flushnext - cause next transmission to have a flush
- */
- sock_flushnext( sock_type *s)
- {
- if (s->tcp.ip_type == TCP_PROTO )
- s->tcp.flags |= tcp_FlagPUSH;
- }
- /*
- * sock_putc - put a character
- * - no expansion but flushes on '\n'
- * - returns character
- */
- byte sock_putc( sock_type *s, byte c )
- {
- if (( c == '\n') || ( c == '\r'))
- sock_flushnext( s );
- sock_write( s, &c, 1 );
- return( c );
- }
-
- word sock_getc( sock_type *s )
- {
- char ch;
- sock_read( s, &ch, 1 );
- return( ch );
- }
-
- /*
- * sock_puts - does not append carriage return in binary mode
- * - returns length
- */
- sock_puts( sock_type *s, byte *dp )
- {
- int len;
- len = strlen( dp );
- sock_flushnext( s );
- sock_write( s, dp, len );
- if (s->tcp.sock_mode & TCP_MODE_ASCII )
- sock_write( s, "\r\n", 2 );
- return( len );
- }
-
- /*
- * sock_update - update the socket window size to the other guy
- */
- static sock_update( tcp_Socket *s )
- {
- if (s->ip_type == TCP_PROTO) {
- if ( s->rdatalen < ( 3 * s->rmaxdatalen) / 4 )
- tcp_send( s ); /* update the window */
- else
- tcp_sendsoon( s );
- }
- }
- /*
- * sock_gets - read a string from any socket
- * - return length of returned string
- * - removes end of line terminator
- */
- word sock_gets( sock_type *s, byte *dp, int n )
- {
- int len, templen;
- char *src_p, *temp, *temp2;
- char *endn, *endr; /* used since we do not list strpbrk */
- word *np;
-
- char *src, *dest, *tempp;
-
- if ( n > tcp_MaxBufSize ) n = tcp_MaxBufSize;
-
- if ( s->udp.ip_type == UDP_PROTO ) {
- src_p = s->udp.rdata;
- np = &s->udp.rdatalen;
- } else {
- src_p = s->tcp.rdata;
- np = &s->tcp.rdatalen;
- }
-
- src_p[ *np ] = 0; /* terminate string */
- strncpy( dp, src_p, n ); /* copy everything */
- dp[ n-1 ] = 0; /* terminate */
-
- if (temp = strchr( dp, '\n')) *temp = 0;
- if (temp2= strchr( dp, '\r')) *temp2= 0;
- len = strlen( dp );
-
- /* skip if there were no crs or lfs ??? */
- if (!temp2 && !temp && ( strlen( dp ) < n - 1) ) {
-
- if ( s->udp.ip_type == TCP_PROTO &&
- s->tcp.state != tcp_StateESTAB &&
- s->tcp.state != tcp_StateESTCL &&
- s->tcp.state != tcp_StateCLOSWT )
- /* take what we can get from this connection */;
- else {
- *dp = 0;
- return( 0 );
- }
- }
-
- /* skip over \n and \r but stop on end */
- #ifndef OLD
- if ( temp ) templen = FP_OFF( temp ) - FP_OFF( dp );
- else if ( temp2 ) templen = FP_OFF( temp2 ) - FP_OFF( dp );
- else templen = len + 1;
-
- if (templen) {
- ++templen;
- memmove( src_p, &src_p[ templen ], *np -= templen);
- } else
- * np = 0;
- #else
- temp = &src_p[ len + 1 ];
- while ( *temp && ( ( *temp == '\n' ) || (*temp == '\r')))
- temp++;
-
- if (*temp)
- memmove( src_p, temp, *np = strlen( temp ));
- else
- *np = 0;
- #endif // OLD
-
- sock_update( (tcp_Socket *)s ); /* new window */
- return( len );
- }
-
-
- /*
- * sock_dataready - returns number of bytes waiting to be ready
- * - if in ASCII mode, return 0 until a line is present
- * or the buffer is full
- */
- word sock_dataready( sock_type *s )
- {
- int len;
- char *p;
-
- if ((len = s->tcp.rdatalen) == -1) return( -1 );
-
- if (s->tcp.sock_mode & TCP_MODE_ASCII) {
- if ( len == tcp_MaxBufSize )
- return( tcp_MaxBufSize );
- /* check for terminating \n \r */
- p = s->tcp.rdata;
- if ( strchr( p , '\n') || strchr( p, '\r'))
- return( len );
- return( 0 );
- } else
- return( len );
- }
-
- sock_established( sock_type *s )
- {
- switch ( s->tcp.ip_type ) {
- case UDP_PROTO :
- return( 1 );
- case TCP_PROTO :
- return( s->tcp.state == tcp_StateESTAB ||
- s->tcp.state == tcp_StateESTCL ||
- s->tcp.state == tcp_StateCLOSWT );
- default :
- return( 0 );
- }
- }
-
- sock_close( s )
- sock_type *s;
- {
- switch (s->udp.ip_type) {
- case UDP_PROTO :
- udp_close( s );
- break;
- case TCP_PROTO :
- tcp_close( (tcp_Socket *)s );
- tcp_tick( s );
- break;
- }
- }
-
-
- /*
- * _ip_delay0 called by macro sock_wait_established()
- * _ip_delay1 called by macro sock_wait_intput()
- * _ip_delay2 called by macro sock_wait_closed();
- *
- */
-
- _ip_delay0( s, timeoutseconds, fn, statusptr )
- sock_type *s;
- int timeoutseconds;
- procref fn;
- int *statusptr;
- {
- int status;
- ip_timer_init( s , timeoutseconds );
- do {
- if ( s->tcp.ip_type == TCP_PROTO ) {
- if ( tcp_established( (tcp_Socket *)s )) {
- status = 0;
- break;
- }
- }
- kbhit(); /* permit ^c */
- if ( !tcp_tick( s )) {
- s->tcp.err_msg = "Host refused connection";
- status = -1; /* get an early reset */
- break;
- }
- if ( ip_timer_expired( s )) {
- sock_close( s );
- status = -1;
- break;
- }
- if ( fn ) if (status = fn(s)) break;
- if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
- if ( s->tcp.ip_type == UDP_PROTO ) {
- status = 0;
- break;
- }
- } while ( 1 );
- if (statusptr) *statusptr = status;
- return( status );
- }
-
- _ip_delay1( s, timeoutseconds, fn, statusptr)
- sock_type *s;
- int timeoutseconds;
- procref fn;
- int *statusptr;
- {
- int status;
- ip_timer_init( s , timeoutseconds );
-
- sock_flush( s ); /* new enhancement */
-
- do {
- if ( sock_dataready( s )) {
- status = 0;
- break;
- }
- kbhit(); /* permit ^c */
- if ( !tcp_tick( s )) {
- status = 1;
- break;
- }
- if ( ip_timer_expired( s )) {
- sock_close( s );
- status = -1;
- break;
- }
- if (fn) {
- if (status = fn(s))
- break;
- }
- if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
- } while ( 1 );
- if (statusptr) *statusptr = status;
- return( status );
- }
-
- _ip_delay2( s, timeoutseconds, fn, statusptr)
- sock_type *s;
- int timeoutseconds;
- procref fn;
- int *statusptr;
- {
- int status;
- ip_timer_init( s , timeoutseconds );
-
- if (s->tcp.ip_type != TCP_PROTO ) return( 1 );
-
- do {
- /*
- while ( sock_dataready( s ))
- sock_fastread( s, &status, 1 );
- */
- kbhit(); /* permit ^c */
- if ( !tcp_tick( s )) {
- status = 1;
- break;
- }
- if ( ip_timer_expired( s )) {
- sock_abort( (tcp_Socket *)s );
- status = -1;
- break;
- }
- if (fn) {
- if (status = fn(s))
- break;
- }
- if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
-
- } while ( 1 );
- if (statusptr) *statusptr = status;
- return( status );
- }
-
-
- char *rip( char *s )
- {
- char *temp;
-
- if (temp = strchr( s, '\n')) *temp = 0;
- if (temp = strchr( s, '\r')) *temp = 0;
- return( s );
- }
-