PCTCP.C
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:93k
源码类别:

操作系统开发

开发平台:

DOS

  1. /* DEBUG flag may be set for my internal playing */
  2. /*
  3. #define DEBUG
  4. */
  5. /*
  6.  *  PCTCP - the true worker of Waterloo TCP
  7.  *        - contains all opens, closes, major read/write routines and
  8.  *          basic IP handler for incomming packets
  9.  *        - NOTE: much of the TCP/UDP/IP layering is done at the data structure
  10.  *          level, not in separate routines or tasks
  11.  *
  12.  */
  13. #include <copyright.h>
  14. #include <time.h>
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #include <stdlib.h>
  18. #include <conio.h>
  19. #include <string.h>
  20. #include <mem.h>
  21. #include <dos.h>
  22. #include <values.h>
  23. #include "wattcp.h"
  24. #include "elib.h"
  25. static void udp_handler(in_Header *ip);
  26. static udp_write(udp_Socket *s, byte *datap, int len, word offset);
  27. static int udp_read(udp_Socket *s, byte *datap, int maxlen);
  28. static void tcp_Retransmitter(void);
  29. #define TCP_LOCAL 0x4000
  30. #define TCP_SAWCR 0x2000                // S. Lawson
  31. /* statics */
  32. //static tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len);
  33. static void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len, // 94.11.19
  34.                                     tcp_PseudoHeader *ph, word *flags); // S. Lawson
  35. static char far *mono = (char far *)0xb0000000L;
  36. static char far *colour = (char far *)0xb8000000L;
  37. static initialized = 0;
  38. void (*system_yield)() = NULL;      /* 2000.4.14 EE */
  39. extern int multihomes;
  40. extern word _pktipofs;
  41. void (*_dbugxmit)( sock_type *s, in_Header *inp, void *phdr, unsigned line ) = NULL;
  42. void (*_dbugrecv)( sock_type *s, in_Header *inp, void *phdr, unsigned line ) = NULL;
  43. void (*wattcpd)(void) = NULL;
  44. char *_hostname = "012345678901234567890123456789012345678901234567890";
  45. word _mss = ETH_MSS;            // maximum size of *IP DATAGRAM*
  46. word sock_data_timeout = 120;  /* after 2 minutes we give up EE 99.08.23 */
  47. char *_wattcp = WATTCP_C;
  48. static void tcp_handler(in_Header *ip);
  49. static void udp_handler(in_Header *ip);
  50. static void tcp_unthread(tcp_Socket *ds);
  51. static void tcp_abort(tcp_Socket *s);
  52. void tcp_sendsoon(tcp_Socket *s );
  53. static void tcp_send(tcp_Socket *s, int line);
  54. static void tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp);
  55. static udp_close(udp_Socket *ds);
  56. // AGW
  57. // unsigned long later than for seq and ack comparisons -- allow for roll over
  58. #define laterthan(x,y) ((long)((x)-(y))>0)
  59. /*
  60.  * sock_yield - enable user defined yield function
  61.  */
  62. int sock_yield( tcp_Socket *s, void (*fn)( void ) )
  63. {
  64.     if ( s )
  65.         s->usr_yield = fn;
  66.     else
  67.         system_yield = fn;
  68.     return( 0 );
  69. }
  70. /*
  71.  * sock_mode - set binary or ascii - affects sock_gets, sock_dataready
  72.  *           - set udp checksums
  73.  */
  74. word sock_mode( sock_type *s, word mode )
  75. {
  76.      return( s->tcp.sock_mode = (s->tcp.sock_mode & 0xfffc) | mode);
  77. }
  78. /*
  79.  * ip user level timer stuff
  80.  *   void ip_timer_init( void *s, int delayseconds )
  81.  *   int  ip_timer_expired( void *s )
  82.  *      - 0 if not expired
  83.  */
  84. static unsigned long far *realclock = (unsigned long far *)0x000046cL;
  85. #define MAXTICKS 0x1800b0L
  86. void ip_timer_init( sock_type *s , int delayseconds )
  87. {
  88.     if (delayseconds)
  89.         s->tcp.usertimer = set_timeout( delayseconds );
  90.     else
  91.         s->tcp.usertimer = 0;
  92. }
  93. int ip_timer_expired( sock_type *s )
  94. {
  95.     if (! s->tcp.usertimer)     /* cannot expire */
  96.         return( 0 );
  97.     return( chk_timeout( s->tcp.usertimer));
  98. }
  99. longword MsecClock( void )
  100. {
  101.     return( (*realclock) * 55L);
  102. }
  103. static long make_timeout( word timeout )
  104. {
  105.     if ( timeout ) return( set_timeout( timeout ));
  106.     return( 0 );
  107. }
  108. #ifdef NOTUSED    /* 94.11.27 -- not used? */
  109. /*
  110.  * check_timeout - test agains timeout clock - account for overflow
  111.  */
  112. static int check_timeout( unsigned long timeout )
  113. {
  114.     if (timeout) return( chk_timeout( timeout ));
  115.     return( 0 );
  116. }
  117. #endif
  118. /*
  119.  * Local IP address
  120.  */
  121. longword my_ip_addr = 0L;       /* for external references */
  122. longword sin_mask = 0xfffffe00L;
  123. longword sin_gate = 0x0;
  124. /*
  125.  * IP identification numbers
  126.  */
  127. static int ip_id = 0;                   /* packet number */
  128. static int next_tcp_port = 1024;        /* auto incremented */
  129. static int next_udp_port = 1024;
  130. //static
  131. tcp_Socket *tcp_allsocs = NULL;
  132. static udp_Socket *udp_allsocs = NULL;
  133. /* Timer definitions */
  134. #define RETRAN_STRAT_TIME  1     /* in ticks - how often do we check retransmitter tables*/
  135. #define tcp_RETRANSMITTIME 3     /* interval at which retransmitter is called */
  136. #define tcp_LONGTIMEOUT 31       /* timeout for opens */
  137. #define tcp_TIMEOUT 13           /* timeout during a connection */
  138. #define LASTACK_TIMEOUT 10              // timeout in the LASTACK state added AGW 5th Jan 2001
  139. // S. Lawson - define a short TIME_WAIT timeout that can be set in the
  140. //             makefile.  It should be from .5 to 4 minutes (2MSL) but it's
  141. //             not really practical for us.  2 secs will hopefully handle the
  142. //             case where ACK must be retransmitted, but can't protect future
  143. //             connections on the same port from old packets.
  144. #if !defined(TW_TO)
  145. #define TW_TO 2
  146. #endif
  147. word debug_on = 0;
  148. /*
  149.  * look for bugs
  150.  */
  151. int tcp_checkfor( sock_type *t )
  152. {
  153.     tcp_Socket *p;
  154.     for ( p = tcp_allsocs ; p ; p = p->next )
  155.         if ( p == (tcp_Socket *)t ) return( 1 );
  156.     return( 0 );
  157. }
  158. /*
  159.  * Shut down the card and all services
  160.  */
  161. void tcp_shutdown( void )
  162. {
  163.     while (tcp_allsocs)
  164.         tcp_abort( tcp_allsocs );
  165.     _eth_release();
  166.     initialized = 0;
  167. }
  168. // S. Lawson - keep an exiting tcp_init()
  169. void tcp_init( void )
  170. {
  171.    int r;
  172.    r=tcp_init_noexit();
  173.    if (r) exit(r);
  174. }
  175. /*
  176.  * tcp_init - Initialize the tcp implementation
  177.  *          - may be called more than once without hurting
  178.  */
  179. int tcp_init_noexit( void )             // S. Lawson
  180. {
  181.     extern int _arp_last_gateway;
  182.     extern int _last_nameserver;
  183.     if (!initialized) {
  184.         /* initialize ethernet interface */
  185.         initialized = 1;
  186. // S. Lawson    _eth_init();
  187.         if (_eth_init()) return 1;      // S. Lawson
  188.         /* reset the various tables */
  189.         _arp_last_gateway = 0;  /* reset the gateway table */
  190.         _last_nameserver = 0;   /* reset the nameserver table */
  191.         _last_cookie = 0;       /* eat all remaining crumbs */
  192.         *_hostname = 0;         /* reset the host's name */
  193.         _eth_free( 0 );
  194.         next_udp_port = next_tcp_port = 1024 + ((int)(*realclock >> 7 )& 0x1ff);
  195.     }
  196.     return 0;                   // S. Lawson
  197. }
  198. // S. Lawson - initialize the port number counters
  199. void tcp_set_ports(word tcp_base, word udp_base) {
  200.     if (tcp_base) next_tcp_port=(int) tcp_base;
  201.     if (udp_base) next_udp_port=(int) udp_base;
  202. }
  203. // S. Lawson - return current port number counters
  204. void tcp_get_ports(word *tcp_base, word *udp_base) {
  205.     if (tcp_base) *tcp_base=(word) next_tcp_port;
  206.     if (udp_base) *udp_base=(word) next_udp_port;
  207. }
  208. /*
  209.  * Checks for bugs when compiling in large model C compiler
  210.  *
  211.  * Borland C uses a 4K stack by default.  In all memory models the
  212.  * stack grows down toward the heap.
  213.  *
  214.  * If you accidentally place tcp_Socket onto the stack (like by making
  215.  * it an automatic variable), then you will have already used up that
  216.  * whole 4K and then some!
  217.  *
  218.  * In large model, this will mess up the data space in a major way
  219.  * because the stack starts at SS:_stklen, or SS:1000, so you will
  220.  * wrap the SP pointer back around to FFFE and start writing over
  221.  * the far heap.  Yuck.
  222.  *
  223.  * In small model it usually doesn't kill your application because
  224.  * you would have to be down to your last 4K of memory and this is
  225.  * not as common.
  226.  *
  227.  * The solutions: declare your sockets as static, or put them on the
  228.  * heap, or bump up your stack size by using the global special variable:
  229.  *
  230.  * unsigned _stklen = 16536;    // set stack to 16 k
  231.  */
  232. static void largecheck( void *s, int size )
  233. {
  234. #ifdef __TURBOC__
  235.     if ( (word)(FP_OFF(s)) > (word)(-size)) {
  236.         outs("ERROR: user stack size errorn");
  237.         exit( 3 );
  238.     }
  239. #endif
  240. }
  241. /*
  242.  * findfreeport - return unused local port
  243.  *              - oldport = 0:normal port, 1:special port (513-1023)
  244.  *              - we need not be this picky, but it doesn't hurt
  245.  * S. Lawson - added TCP/UDP flag so we can pick unique ports and
  246.  *             avoid reconnecting with a socket in TIME_WAIT (the
  247.  *             original "oldport+510" scan needs a rewrite someday)
  248.  */
  249. static word findfreeport( word oldport, word proto_tcp )
  250. {
  251.     word temp;
  252.     tcp_Socket *s;
  253. // S. Lawson - s/b > 1     if (( oldport > 0 ) && (oldport < 0xffff))
  254.     if (( oldport > 1 ) && (oldport < 0xffff))          // S. Lawson
  255.         return( oldport );
  256. // S. Lawson - start
  257. //  if ( oldport == 0 ) oldport = 1025;
  258.     if ( oldport == 0) {
  259.        if (proto_tcp) {
  260.           if ((oldport=next_tcp_port++)>=32767-510) next_tcp_port=1024;
  261.        } else {
  262.           if ((oldport=next_udp_port++)>=32767-510) next_udp_port=1024;
  263.        }
  264.     }
  265. // S. Lawson - end
  266.     else oldport = 513;
  267.     for ( temp = oldport ; temp < oldport + 510 ; ++temp ) {
  268.       if (!proto_tcp) {                         // S. Lawson
  269.         if (( s = (tcp_Socket*)udp_allsocs) != NULL ) {
  270.             while ( s->next && (s->myport != temp))
  271.                 s = (tcp_Socket*)s->next;
  272.             if ( s->myport == temp ) continue;
  273.         }
  274.       } else {                                          // S. Lawson
  275.         if ( (s = tcp_allsocs ) != NULL ) {
  276.             while ( s->next && (s->myport != temp ))
  277.                 s = s->next;
  278.             if ( s->myport == temp ) continue;
  279.         }
  280.       }                                                 // S. Lawson
  281.       break;
  282.     }
  283.     return( temp );
  284. }
  285. /* socket, localport, destaddress */
  286. int udp_open( udp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler )
  287. {
  288.     udp_close( s );
  289.     largecheck( s, sizeof( udp_Socket ));
  290.     memset( s, 0, sizeof( udp_Socket ));
  291.     s->rdata = s->rddata;
  292.     s->maxrdatalen = tcp_MaxBufSize;
  293.     s->ip_type = UDP_PROTO;
  294.     lport = findfreeport(lport, false);         // S. Lawson - added "false"
  295.     s->myport = lport;
  296.     s->myaddr = my_ip_addr;
  297.     /* check for broadcast */
  298.     if ( (long)(ina) == -1 )
  299.         memset( &s->hisethaddr, 0xff, sizeof( eth_address ));
  300. //  EE 2000.9.13
  301. //  handle late binding IP
  302.     else if ( ina == 0 )
  303. //      Changed.  EE 2000.9.13 we want this zeroed so udp_writes will arp_resolve
  304. //                once we have bound to a particular IP and
  305.         memset( &s->hisethaddr, 0x00, sizeof( eth_address ));
  306.     else if ( ! _arp_resolve(ina, &s->hisethaddr, 0) )
  307.         return( 0 );
  308.     s->hisaddr = ina;
  309.     s->hisport = port;
  310.     s->dataHandler = datahandler;
  311.     s->usr_yield = system_yield;
  312.     s->safetysig = SAFETYUDP;
  313.     s->next = udp_allsocs;
  314.     udp_allsocs = s;
  315.     return( 1 );
  316. }
  317. /*
  318.  * Actively open a TCP connection to a particular destination.
  319.  *      - 0 on error
  320.  */
  321. int tcp_open( tcp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler )
  322. {
  323.     largecheck( s, sizeof( tcp_Socket ));   /* stack space warnings */
  324.     tcp_unthread(s);                        /* just in case not totally closed */
  325.     memset( s, 0, sizeof( tcp_Socket));
  326.     s->rdata = s->rddata;
  327.     s->maxrdatalen = tcp_MaxBufSize;
  328.     s->ip_type = TCP_PROTO;
  329.     // S. Lawson - _mss is *IP DATAGRAM* size, set TCP MSS here
  330. //    s->mss = _mss;
  331.     s->mss = _mss - sizeof( in_Header ) - sizeof ( tcp_Header );
  332.     s->state = tcp_StateSYNSENT;
  333.     s->timeout = set_timeout( tcp_LONGTIMEOUT );
  334.     s->cwindow = 1;
  335.     s->wwindow = 0;     /* slow start VJ algorithm */
  336.     s->vj_sa = 4;      /* about 250 ms */
  337.     lport = findfreeport( lport, true );  /* get a nonzero port val (S. Lawson - added true) */
  338.     s->myaddr = my_ip_addr;
  339.     s->myport = lport;
  340.     if ( ina - my_ip_addr <= multihomes ) return( 0 );
  341.     if ( ! _arp_resolve(ina, &s->hisethaddr, 0) )
  342.         return( 0 );
  343.     s->hisaddr = ina;
  344.     s->hisport = port;
  345.     s->seqnum = intel( set_timeout( 1 )) & 0xffff0000uL;
  346.     s->datalen = 0;
  347.     s->flags = tcp_FlagSYN;
  348.     s->unhappy = true;
  349.     s->dataHandler = datahandler;
  350.     s->usr_yield = system_yield;
  351.     s->frag[0]=s->frag[1]=0L;           // S. Lawson
  352.     s->safetysig = SAFETYTCP;       /* insert into chain */
  353.     s->next = tcp_allsocs;
  354.     tcp_allsocs = s;
  355.     s->rtt_delay = s->rtt_smooth = 18;  /* one second startup */
  356.     tcp_send(s, __LINE__ );
  357.     s->rtt_time = set_timeout( 1 );
  358.     return( 1 );
  359. }
  360. /*
  361.  * Passive open: listen for a connection on a particular port
  362.  */
  363. int tcp_listen( tcp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler, word timeout )
  364. {
  365.     largecheck( s, sizeof( tcp_Socket ));
  366.     tcp_unthread(s);                        /* just in case not totally closed */
  367.     memset( s, 0, sizeof( tcp_Socket));
  368.     s->rdata = s->rddata;
  369.     s->maxrdatalen = tcp_MaxBufSize;
  370.     s->ip_type = TCP_PROTO;
  371.     // S. Lawson - _mss is *IP DATAGRAM* size, set TCP MSS here
  372. //    s->mss = _mss;
  373.     s->mss = _mss - sizeof( in_Header ) - sizeof ( tcp_Header );
  374.     s->cwindow = 1;
  375.     s->wwindow = 0;     /* slow start VJ algorithm */
  376. /*    s->vj_sa = 36;      /* about 250 ms */
  377. /* tcpwinfix -- mdurkin */
  378.     s->vj_sa = 4;      /* about 250 ms */    /* was wrong val 95.05.02 */
  379.     s->state = tcp_StateLISTEN;
  380.     if ( !timeout ) s->timeout = 0; /* forever... */
  381.     else s->timeout = set_timeout( timeout );
  382.     lport = findfreeport( lport, true );  /* get a nonzero port val (S. Lawson - added true)*/
  383.     s->myport = lport;
  384.     s->hisport = port;
  385.     s->hisaddr = ina;
  386.     s->seqnum = intel( (word)(s));
  387.     s->datalen = 0;
  388.     s->flags = 0;
  389.     s->unhappy = false;
  390.     s->dataHandler = datahandler;
  391.     s->usr_yield = system_yield;
  392.     s->frag[0]=s->frag[1]=0L;           // S. Lawson
  393.     s->safetysig = SAFETYTCP;       /* insert into chain */
  394.     s->next = tcp_allsocs;
  395.     tcp_allsocs = s;
  396.     return( 1 );
  397. }
  398. static udp_close( udp_Socket *ds )
  399. {
  400.     udp_Socket *s, **sp;
  401.     sp = &udp_allsocs;
  402.     for (;;) {
  403.         s = *sp;
  404.         if ( s == ds ) {
  405.             *sp = s->next;
  406.             break;
  407.         }
  408.         if ( !s ) break;
  409.         if ( ! s->err_msg ) s->err_msg = "UDP Close called";
  410.         sp = &s->next;
  411.     }
  412.     return( 0 );
  413. }
  414. /*
  415.  * Send a FIN on a particular port -- only works if it is open
  416.  *   Must still allow receives
  417.  */
  418. static void tcp_close( tcp_Socket *s )
  419. {
  420.     if ( s->ip_type != TCP_PROTO )
  421.         return;
  422.     if ( s->state == tcp_StateESTAB ||
  423.                 s->state == tcp_StateESTCL ||
  424.                 s->state == tcp_StateSYNREC )
  425.         {
  426.                 if ( s->datalen )      /* must first flush all data */
  427.                 {
  428.                     s->flags |= tcp_FlagPUSH | tcp_FlagACK;
  429.                     if ( s->state < tcp_StateESTCL )
  430.                     {
  431.                                 s->state = tcp_StateESTCL;
  432.                                 tcp_sendsoon( s );
  433.                 }
  434.                 }
  435.                 else
  436.                 { /* really closing */
  437.                     s->flags = tcp_FlagACK | tcp_FlagFIN;
  438.                     if (!s->err_msg)
  439.                                 s->err_msg = "Connection closed normally";
  440.                     s->state = tcp_StateFINWT1;
  441.                     s->timeout = set_timeout( tcp_TIMEOUT ); /* should be a pretty lengthy time */ /* S. Lawson - make longer */
  442.                 tcp_send( s, __LINE__ );
  443.                 }
  444.                 s->unhappy = true;
  445.     }
  446.     else if (s->state == tcp_StateCLOSWT )
  447.     { /* need to ack the fin and get on with it */
  448.                 s->timeout = set_timeout( LASTACK_TIMEOUT );    // Added AGW 6 Jan 2001
  449.                 s->state = tcp_StateLASTACK;
  450.                 s->flags |= tcp_FlagFIN;
  451.                 tcp_send( s, __LINE__ );
  452.                 s->unhappy = true;
  453.             // S. Lawson - Added per (10-Jun 1997, GV)
  454.     }
  455.     else if (s->state == tcp_StateSYNSENT)
  456.     {
  457.                 s->state = tcp_StateCLOSED;
  458.                 tcp_unthread (s);               /* unlink failed connect */
  459.     }
  460. }
  461. /*
  462.  * Abort a tcp connection
  463.  */
  464. static void tcp_abort( tcp_Socket *s )
  465. {
  466.     if (!s->err_msg) s->err_msg = "TCP_ABORT";
  467.     if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
  468.         s->flags = tcp_FlagRST  | tcp_FlagACK ;
  469.         s->unhappy = true;
  470.         tcp_send(s, __LINE__);
  471.     }
  472.     s->unhappy = false;
  473.     s->datalen = 0;
  474.     s->ip_type = 0;
  475.     s->state = tcp_StateCLOSED;
  476. /*    if (s->dataHandler) s->dataHandler(s, 0, -1); */
  477.     tcp_unthread(s);
  478. }
  479. void sock_abort( sock_type *s )
  480. {
  481.     if ( s->tcp.ip_type == TCP_PROTO )
  482.         tcp_abort( (tcp_Socket *)s );
  483.     else
  484.         udp_close( (udp_Socket *)s );
  485. }
  486. /*
  487.  * tcp_sendsoon - schedule a transmission pretty soon
  488.  *              - this one has an imperfection at midnight, but it
  489.  *                is not significant to the connection performance
  490.  */
  491. void tcp_sendsoon( tcp_Socket *s )
  492. {
  493.     longword temp;
  494.     if (s->ip_type == TCP_PROTO ) {
  495.         temp = set_ttimeout( 1 );
  496.         if ( temp == s->rtt_time && s->rto < 2 && s->recent == 0 ) {
  497.             s->karn_count = 0;
  498.             tcp_send( s, __LINE__ );
  499.             s->recent = 1;
  500.             return;
  501.         }
  502.         if ((s->unhappy || s->datalen > 0 || s->karn_count == 1)
  503.           && (s->rtt_time < temp && s->rtt_time != 0))  // S. Lawson - handle 0
  504.             return;
  505.         s->rtt_time = set_ttimeout( 1 + (s->rto >> 4) );
  506.         s->karn_count = 1;
  507.     }
  508. }
  509. /*
  510.  * Retransmitter - called periodically to perform tcp retransmissions
  511.  */
  512. static longword retran_strat = 0L; /* timeout retran strategy */
  513. static void tcp_Retransmitter( void )
  514. {
  515.     tcp_Socket *s;
  516.     /* only do this once per RETRAN_STRAT_TIME milliseconds */
  517.     if ( !chk_timeout( retran_strat ))
  518.         return;
  519.     retran_strat = set_ttimeout( RETRAN_STRAT_TIME );
  520.     for ( s = tcp_allsocs; s; s = s->next ) {
  521.         // S. Lawson - possible to be closed but still queued
  522.         if ( s->state==tcp_StateCLOSED ) {
  523.            if ( s->rdatalen == 0) tcp_unthread(s);
  524.            continue;
  525.         }
  526.         if ( s->datalen > 0 || s->unhappy || s->karn_count == 1 ) {
  527.             /* retransmission strategy */
  528. // S. Lawson - clear the timeout once it fires (thanks GV)
  529. #ifdef NOTUSED
  530.             if ( chk_timeout( s->rtt_time)) {
  531. #else
  532.             if ( s->rtt_time && chk_timeout( s->rtt_time )) {
  533.                s->rtt_time = 0;
  534. #endif
  535. #ifdef DEBUG
  536.     if(debug_on >1) printf("regular retran TO set unacked back to 0 from %un", s->unacked);
  537. #endif //DEBUG
  538.                 /* strategy handles closed windows   J.D. + E.E. */
  539.                if (s->window == 0 && s->karn_count == 2)
  540.                   s->window = 1;
  541.                 if ( s->karn_count == 0 ) {
  542.                     /* if really did timeout */
  543.                     s->karn_count = 2;
  544.                     s->unacked = 0;
  545.                     /* use the backed off rto - implied, no code necessary */
  546.                     /* reduce the transmit window */
  547.                     s->cwindow =  ((s->cwindow + 1) * 3) >> 2;
  548.                     if ( s->cwindow == 0 ) s->cwindow = 1;
  549.                     s->wwindow = 0;
  550.                 }
  551.                 if (s->datalen)
  552.                     s->flags |= tcp_FlagPUSH | tcp_FlagACK;
  553.                 tcp_send(s, __LINE__);
  554.             }
  555.             /* EE 99.08.23 */
  556.             if ( s->datatimer )
  557.                 if ( chk_timeout( s->datatimer )) {
  558.                     sock_abort( (sock_type *) s );
  559.                 }
  560.         }
  561.         /* handle inactive tcp timeouts */
  562.         if ( sock_inactive && s->inactive_to ) {
  563.             if ( chk_timeout( s->inactive_to)) {
  564.                 /* this baby has timed out */
  565.                 s->err_msg = "Connection timed out - no activity";
  566.                 sock_close( (sock_type *) s );
  567.             }
  568.         }
  569.         if ( s->timeout && chk_timeout( s->timeout)) {
  570.             if ( s->state == tcp_StateTIMEWT ) {
  571.                 s->state = tcp_StateCLOSED;
  572.                 tcp_unthread(s);
  573.                 break;
  574.             } else if (s->state != tcp_StateESTAB && s->state != tcp_StateESTCL ) {
  575.                 s->err_msg = "Timeout, aborting";
  576.                 tcp_abort(s);
  577.                 break;
  578.             }
  579.         }
  580.     }
  581.     /* do our various daemons */
  582.     if ( wattcpd ) (*wattcpd)();
  583. }
  584. /*
  585.  * Unthread a socket from the tcp socket list, if it's there
  586.  */
  587. static void tcp_unthread( tcp_Socket *ds )
  588. {
  589.     tcp_Socket *s, **sp;
  590.     if (!ds->rdatalen || (ds->state > tcp_StateESTCL))
  591.                 ds->ip_type = 0;                /* fail io */
  592.     ds->state = tcp_StateCLOSED;   /* tcp_tick needs this */
  593.     sp = &tcp_allsocs;
  594.     for (;;) {
  595.         s = *sp;
  596.         if ( s == ds ) {
  597.             *sp = s->next;
  598.             continue;           /* unthread multiple copies if necessary */
  599.         }
  600.         if ( !s ) break;
  601.         sp = &s->next;
  602.     }
  603. }
  604. /*
  605.  * tcp_tick - called periodically by user application
  606.  *          - returns 1 when our socket closes (S. Lawson - wrong: 0)
  607.  *          - called with socket parameter or NULL
  608.  */
  609. int tcp_tick( sock_type *s )
  610. {
  611.     in_Header *ip;
  612.     static longword timeout = 0;
  613.     static longword start = 0;
  614.     extern int dhcp_expired(void);      /* S. Lawson - in pcbootp.c */
  615. /*    int x; */
  616.     int packettype;
  617.     /* S. Lawson - handle DHCP lease expiration */
  618.     if (dhcp_expired()) {
  619.                 if ( s ) s->udp.err_msg = "DHCP lease expired";
  620.                 return 0;
  621.     }
  622.     /* finish off dead sockets */
  623.     if ( s ) {
  624.                 if (( s->tcp.ip_type == TCP_PROTO ) &&
  625.                     ( s->tcp.state == tcp_StateCLOSED ) &&
  626.                     ( s->tcp.rdatalen == 0 )) {
  627.                         tcp_unthread( & s->tcp );
  628.                         s->tcp.ip_type = 0;
  629.                 }
  630.     }
  631.     /* plan our next retransmit */
  632.     if ( !timeout )
  633.         timeout = make_timeout( tcp_RETRANSMITTIME );
  634.     while ( (ip = (in_Header *)_eth_arrived( (word *) &packettype )) != NULL )
  635.     {
  636.                 start = *realclock;
  637.                 switch ( packettype )
  638.                 {
  639.                 case /*0x800*/ 0x008 :
  640.                     /* do IP */
  641.                     if ( checksum(ip, in_GetHdrlenBytes(ip)) == 0xffff ) {
  642.                         switch ( ip->proto ) {
  643.                             case TCP_PROTO :
  644.                                 tcp_handler(ip);
  645.                                 break;
  646.                             case UDP_PROTO :
  647.                                 udp_handler(ip);
  648.                                 break;
  649.                             case ICMP_PROTO :
  650.                                 icmp_handler(ip);
  651.                                 break;
  652.                         }
  653.                     } else  {
  654. #ifdef DEBUG
  655.                         if (debug_on) outs("nrIP: Bad Checksumnr"); // R. Whitby
  656. #endif
  657.                     }
  658.                     break;
  659.                 case /*0x806*/ 0x608 :
  660.                     /* do arp */
  661.                     _arp_handler( (arp_Header *)ip );
  662.                     break;
  663.                 }
  664.                 if (ip) _eth_free(ip);
  665.                 continue;
  666.     }
  667.     /* check for our outstanding packets */
  668.         tcp_Retransmitter();
  669. // S. Lawson     return( s->udp.ip_type );
  670.     return( s ? s->udp.ip_type : 1 );        /* S. Lawson - change CJ01 */
  671. }
  672. void tcp_set_debug_state( int x )
  673. {
  674.     debug_on = x;
  675. }
  676. /* returns 1 if connection is established */
  677. int tcp_established( tcp_Socket *s )
  678. {
  679.     return( s->state >= tcp_StateESTAB );
  680. }
  681. /*
  682.  * udp_write() handles fragmented UDP by assuming it'll be called
  683.  *     once for all fragments with no intervening calls.  This is
  684.  *     the case in sock_write().
  685.  * Handles upto a hair-under 32K datagrams.  Could be made to handle
  686.  *     upto a hair-under 64K easily...  wanna Erick?
  687.  * Might be possible to test 'offset' for non/zero fewer times to be
  688.  *     more efficient.  Might also be more efficient to use the old
  689.  *     UDP checksum() call when more_frags is false in the first frag
  690.  *     (i.e., not a fragmented dgram).
  691.  * Uses _mss to decide splits which defaults to 1400.  Could pack
  692.  *     more into an Ethernet packet.
  693.  */
  694. #define IP_MF 0x0020               // more fragments, net byte order
  695. static udp_write( udp_Socket *s, byte *datap, int len, word offset )
  696. {
  697.     struct {                    // special pseudo header because need to
  698.         tcp_PseudoHeader ph;    //    compute checksum in two parts (may not
  699.         word checksum2;         //    have all of datagram built at once).
  700.     } ph;
  701.     struct _pkt {
  702.         in_Header  in;
  703.         udp_Header udp;
  704.         int        data;
  705. /*      longword maxsegopt; */
  706.     } *pkt;
  707.     byte *dp;
  708.     in_Header *inp;
  709.     udp_Header *udpp;
  710.     word maxlen;
  711.     int more_frags;
  712.     word origlen = len;
  713.     // S. Lawson - set Ethernet address if not set (possible if we were
  714.     // a passive/broadcast socket
  715.     if (memcmp(&s->hisethaddr, "", 6)==0) {
  716.        /* check for broadcast */
  717.        /* 2001.1.18 changed from -1 */
  718.        if ( s->hisaddr == 0xffffffff || !s->hisaddr )
  719.           memset( &s->hisethaddr, 0xff, sizeof( eth_address ));
  720.        else if ( ! _arp_resolve(s->hisaddr, &s->hisethaddr, 0) )
  721.           return( 0 );
  722.     }
  723.     pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr, /*0x800*/ 8);
  724.     if( offset ) {              // this is not the first fragment
  725.         dp = (byte *) &pkt->udp;    // data goes right after IP header
  726.     } else {
  727.         dp = (byte *) &pkt->data;
  728.         udpp = &pkt->udp;
  729.         /* udp header */
  730.         udpp->srcPort = intel16( s->myport );
  731.         udpp->dstPort = intel16( s->hisport );
  732.         udpp->checksum = 0;
  733.         udpp->length = intel16( UDP_LENGTH + len );
  734.     }
  735.     inp = &pkt->in;
  736.     memset( inp, 0, sizeof( in_Header ));
  737. // S. Lawson - this needs changed to handle DHCP when using 576 MSS
  738. #ifdef NOTUSED
  739.     maxlen = _mss & 0xFFF8;             // make a multiple of 8
  740.     if( !offset ) maxlen -= UDP_LENGTH; // note UDP_LENGTH is 8, so ok
  741. #else
  742.     maxlen = _mss - sizeof( in_Header ) - sizeof ( udp_Header );
  743.     if (offset) {
  744.        maxlen += sizeof (udp_Header);
  745.        maxlen &= 0xFFF8;                // make a multiple of 8
  746.     }
  747. #endif
  748.     if( len > maxlen ) {
  749.         maxlen &= 0xFFF8;               // S. Lawson - multiple of 8
  750.         len = maxlen;
  751.         more_frags = 1;
  752.     } else more_frags = 0;
  753.     inp->length = intel16( sizeof(in_Header) +
  754.                                      (offset ? 0 : UDP_LENGTH) + len );
  755.     movmem(datap, dp, len );
  756.     /* internet header */
  757.     inp->ver = 4;
  758.     inp->hdrlen = 5;
  759.     inp->tos = 0;
  760. /* inp->vht = 0x4500;*/   /* version 4, hdrlen 5, tos 0 */
  761.  /* if offset non-zero, then is part of a prev datagram so don't incr ID */
  762.     inp->identification = intel16( offset ? ip_id : ++ip_id );   /* was post inc */
  763. //    inp->frag = 0;
  764.     inp->frags = (offset ? intel16((offset + UDP_LENGTH) >> 3) : 0);
  765.     if(more_frags) inp->frags |= IP_MF;
  766.     inp->ttl = 254;
  767.     inp->proto = UDP_PROTO;     /* udp */
  768. /* inp->ttlProtocol = (250<<8) + 6; */
  769.     inp->checksum = 0;
  770.     inp->source = intel( s->myaddr );
  771.     inp->destination = intel( s->hisaddr );
  772.     inp->checksum = ~checksum( inp, sizeof(in_Header));
  773.     /* compute udp checksum if desired */
  774.     if(!offset) {  // only first of frags has UDP header for entire UDP dgram
  775.         if ( s->sock_mode & UDP_MODE_NOCHK )
  776.             udpp->checksum = 0;
  777.         else {
  778.             ph.ph.src = inp->source;    /* already INTELled */
  779.             ph.ph.dst = inp->destination;
  780.             ph.ph.mbz = 0;
  781.             ph.ph.protocol = UDP_PROTO; /* udp */
  782.             ph.ph.length = udpp->length;        /* already INTELled */
  783.           /* can't use since may not have the whole dgram built at once */
  784. //          ph.checksum = checksum(&pkt->udp, intel16(ph.length));
  785.           /* this way handles it */
  786.             ph.ph.checksum = checksum(&pkt->udp, UDP_LENGTH);
  787.             ph.checksum2 = checksum(datap, origlen);
  788.             udpp->checksum =  ~checksum(&ph, sizeof(ph));
  789.         }
  790.     }
  791.     if (_dbugxmit) (*_dbugxmit)( (sock_type*)s, inp, udpp, 0 );
  792.     _eth_send( intel16( inp->length ));
  793.     return ( len );
  794. }
  795. /*
  796.  * udp_read - read data from buffer, does large buffering
  797.  */
  798. static int udp_read( udp_Socket *s, byte *datap, int maxlen )
  799. {
  800.     int x;
  801.     if (maxlen < 0) maxlen = MAXINT;
  802.     if (( x = s->rdatalen ) > 0) {
  803.         if ( x > maxlen ) x = maxlen;
  804.         if ( x > 0 ) {
  805.             if (datap) movmem( s->rdata, datap, x );
  806.             if ( s->rdatalen -= x )
  807.                 movmem( s->rdata + x, s->rdata, s->rdatalen);
  808.         }
  809.     }
  810.     return( x );
  811. }
  812. void _udp_cancel( in_Header *ip )
  813. {
  814.     int len;
  815.     udp_Header *up;
  816.     udp_Socket *s;
  817.     /* match to a udp socket */
  818.     len = in_GetHdrlenBytes(ip);
  819.     up = (udp_Header *)((byte *)ip + len);      /* udp frame pointer */
  820.     /* demux to active sockets */
  821.     for ( s = udp_allsocs; s; s = s->next )
  822.         if ( s->hisport != 0 &&
  823.              intel16( up->dstPort ) == s->hisport &&
  824.              intel16( up->srcPort ) == s->myport &&
  825.              intel( ip->destination ) == s->hisaddr ) break;
  826.     if ( !s ) {
  827.         /* demux to passive sockets */
  828.         for ( s = udp_allsocs; s; s = s->next )
  829.             if ( s->hisport == 0 && intel16( up->dstPort ) == s->myport ) break;
  830.     }
  831.     if (s) {
  832.         s->rdatalen = 0;
  833.         s->ip_type = 0;
  834.     }
  835. }
  836. void *_tcp_lookup( longword hisip, word hisport, word myport )
  837. {
  838.     tcp_Socket *s;
  839.     for ( s = tcp_allsocs; s; s = s->next ) {
  840.         if ( ( myport == s->myport ) &&         /* always unique under WATTCP */
  841.              ( hisport == s->hisport ) &&
  842.              ( hisip == s->hisaddr ))
  843.                 return( s );
  844.     }
  845.     return( NULL );
  846. }
  847. void _tcp_cancel( in_Header *ip, int code, char *msg, longword dummyip )
  848. {
  849.     static int in_icmp_redirect = 0;            // smart@actrix.gen.nz
  850.     int len;
  851.     tcp_Socket *s;
  852.     tcp_Header *tp;
  853.     len = in_GetHdrlenBytes(ip);        /* check work */
  854.     tp = (tcp_Header *)((byte *)ip + len);      /* tcp frame pointer */
  855.     /* demux to active sockets */
  856.     for ( s = tcp_allsocs; s; s = s->next ) {
  857.         if ( intel16( tp->srcPort) == s->myport &&
  858.              intel16( tp->dstPort ) == s->hisport &&
  859.              intel( ip->destination ) == s->hisaddr ) {
  860.                 switch (code) {
  861.                     /* halt it */
  862.                     case  1 : if (( s->stress ++ > s->rigid ) &&
  863.                                   ( s->rigid < 100 )) {
  864.                                   s->err_msg = (msg) ?
  865.                                     msg : "ICMP closed connection";
  866.                                   s->rdatalen = s->datalen = 0;
  867.                                   s->unhappy = false;
  868.                                   tcp_abort( s );
  869.                 /*      if (s->dataHandler) s->dataHandler(s, 0, -1); */
  870.                                   break;
  871.                               }
  872.                               // follow through to next case
  873.                     /* slow it down */
  874.                     case  2 : s->cwindow = 1;
  875.                               s->wwindow = 1;
  876.                               s->rto <<= 2;
  877.                               s->vj_sa <<= 2;
  878.                               s->vj_sd <<= 2;
  879.                               break;
  880.                     /* icmp redirect for host */
  881.                     case  5 : /* save his NEW network address */
  882.                         /* Dummy is passed in NW form need to intel! */
  883.                         /* This was a bug fixed QVS - smart@actrix.gen.nz */
  884.                               if (!in_icmp_redirect)
  885.                               {
  886.                                   in_icmp_redirect = 1;
  887.                                   _arp_resolve(intel(dummyip), &s->hisethaddr, 0);
  888.                                   in_icmp_redirect = 0;
  889.                               }
  890.                               break;
  891.                 }
  892.         }
  893.     }
  894. }
  895. static int tcp_read( tcp_Socket *s, byte *datap, int maxlen )
  896. {
  897.     int x;
  898.     long ldiff;                         // S. Lawson
  899.     int diff;                           // S. Lawson
  900.     if (maxlen < 0 ) maxlen = MAXINT;
  901.     if (( x = s->rdatalen) > 0) {
  902.         if ( x > maxlen ) x = maxlen;
  903.         if ( x > 0 ) {
  904.             if (datap) movmem( s->rdata, datap, x );
  905. #ifdef NOTUSED  // S. Lawson - possible data fragment above
  906.             if (( s->rdatalen -= x ) > 0 ) {
  907.                 movmem( s->rdata + x, s->rdata, s->rdatalen );
  908. #else   // S. Lawson
  909.             if (( s->rdatalen -= x ) > 0 || s->frag[0] != 0L) {
  910.                 diff=0;
  911.                 if (s->frag[0] != 0L) {
  912.                    ldiff=s->frag[1] - s->acknum;
  913.                    diff=abs((int) ldiff);
  914.                 }
  915.                 movmem( s->rdata + x, s->rdata, s->rdatalen + diff);
  916. #endif
  917.                 tcp_sendsoon( s );   /* update the window */
  918.             } else
  919.                 tcp_send( s, __LINE__ );      /* update window el-pronto */
  920.         }
  921.     } else if ( s->state == tcp_StateCLOSWT )
  922.         tcp_close( s );
  923.     return( x );
  924. }
  925. /*
  926.  * Write data to a connection.
  927.  * Returns number of bytes written, == 0 when connection is not in
  928.  * established state.
  929.  */
  930. static int tcp_write( tcp_Socket *s, byte *dp, int len )
  931. {
  932.     int x;
  933.     if (len < 0 ) len = MAXINT;
  934.     /* no longer uses tcp_MaxData */
  935.     if ( s->state != tcp_StateESTAB ) len = 0;
  936. // S. Lawson - fixed per GV (behaves badly with user defined buffers)
  937. //  if ( len > (x = s->maxrdatalen - s->datalen) ) len = x;
  938.     if ( len > (x = tcp_MaxBufSize - s->datalen) ) len = x;
  939.     if ( len > 0 ) {
  940.         movmem( dp, s->data + s->datalen, len );
  941.         s->datalen += len;
  942.         s->unhappy = true;      /* redundant because we have outstanding data */
  943.         s->datatimer = set_timeout( sock_data_timeout ); /* EE 99.08.23 */
  944.         if ( s->sock_mode & TCP_LOCAL )
  945.             s->sock_mode &= ~TCP_LOCAL;
  946.         else {
  947.             if ( s->sock_mode & TCP_MODE_NONAGLE ) {
  948.                 tcp_send( s, __LINE__ );
  949.             } else {
  950.                 /* transmit if first data or reached MTU */
  951.                 /* not true MTU, but better than nothing */
  952.                 if (( s->datalen == len ) || ( s->datalen > (s->mss)/2 ))
  953.                     tcp_send( s, __LINE__ );
  954.                 else
  955.                     tcp_sendsoon( s );
  956.             }
  957.         }
  958.     }
  959.     return ( len );
  960. }
  961. /*
  962.  * Send pending data
  963.  */
  964. static void tcp_Flush( tcp_Socket *s )
  965. {
  966.     if ( s->datalen > 0 ) {
  967.         s->flags |= tcp_FlagPUSH;
  968.         if (s->unacked == 0)            // S. Lawson - only if data not moving
  969.            tcp_send(s, __LINE__);
  970.     }
  971. }
  972. /*
  973.  * Handler for incoming packets.
  974.  */
  975. static void udp_handler( in_Header *ip )
  976. {
  977.     udp_Header *up;
  978.     tcp_PseudoHeader ph;
  979.     word len;
  980.     byte *dp;
  981.     longword temp;
  982.     udp_Socket *s;
  983.     temp = intel( ip->destination );
  984.     // temp = ip number
  985.     //     or 255.255.255.255
  986.     //     or sin_mask.255.255
  987.     if ( ((~temp & ~sin_mask) != 0) &&  /* not a broadcast packet*/
  988.         ((( temp - my_ip_addr) > multihomes )   /* not my address */
  989.         && my_ip_addr))                 /* and I know my address */
  990.           return;
  991.     len = in_GetHdrlenBytes(ip);
  992.     up = (udp_Header *)((byte *)ip + len);      /* udp segment pointer */
  993.     len = intel16( up->length );
  994.     /* demux to active sockets */
  995.     for ( s = udp_allsocs; s; s = s->next ) {
  996. #ifdef DEBUG
  997.         if ( s->safetysig != SAFETYUDP ) {
  998.             if (debug_on) outs("nrUDP: Chain Errornr");  // R. Whitby
  999.         }
  1000. #endif
  1001.         if ( (s->hisport != 0) &&
  1002.              (intel16( up->dstPort ) == s->myport) &&
  1003.              (intel16( up->srcPort ) == s->hisport) &&
  1004.              ((intel( ip->destination ) & sin_mask)  == (s->myaddr & sin_mask)) &&
  1005.              (intel( ip->source ) == s->hisaddr )) break;
  1006.     }
  1007. // R. Whitby    if (_dbugrecv) (*_dbugrecv)( (sock_type*)s, ip, up, 0);
  1008.     if ( !s ) {
  1009.         /* demux to passive sockets */
  1010.         for ( s = udp_allsocs; s; s = s->next )
  1011.             if ( ((s->hisaddr == 0) || (s->hisaddr == 0xffffffffuL))
  1012.               && intel16( up->dstPort ) == s->myport ) {
  1013.                 // do we record this information ???
  1014.                 if ( s->hisaddr == 0 ) {
  1015.                     s->hisaddr = intel( ip->source );
  1016.                     s->hisport = intel16( up->srcPort );
  1017.                     // S. Lawson - combined from these observations (alot of
  1018.                     //             explanation to remove one line)
  1019.                     //    Dashui Zhou <dszhou@cs.sdu.edu.cn>
  1020.                     //       ARP answer packet overwrites the first datagram
  1021.                     //       that arrives at a newly opened passive UDP
  1022.                     //       socket. (DZ fix moved _arp_resolve)
  1023.                     //    CpV <crudesoft@yahoo.com>
  1024.                     //       _arp_resolve() calls tcp_tick() which calls
  1025.                     //       calls this udp_handler() again (recurses)
  1026.                     //       Anyway, we don't need to resolve now, we can
  1027.                     //       resolve when we want to send something.
  1028. //                  _arp_resolve(intel(ip->source), &s->hisethaddr, 0);
  1029.                     // take on value of expected destination unless it
  1030.                     // is broadcast
  1031.                     if ( (intel(~ip->destination) & ~sin_mask) != 0 )
  1032.                         s->myaddr = intel( ip->destination );
  1033.                 }
  1034.                 break;
  1035.             }
  1036.     }
  1037. #ifdef NOTUSED      // S. Lawson - "passive sockets" scan above does this!
  1038.     if ( !s ) {
  1039.         /* demux to broadcast sockets */
  1040.         // S. Lawson - CpV <crudesoft@yahoo.com> has a change here that
  1041.         // causes broadcasts to go to a socket even if it is bound to a
  1042.         // remote IP address - I'm not including this because binding to
  1043.         // a specific machine should imply you're not interested in getting
  1044.         // packets from other machines on that socket.  You can always keep
  1045.         // a socket bound to the broadcast address for receiving broadcasts.
  1046.         for ( s = udp_allsocs; s; s = s->next )
  1047.             if ( (s->hisaddr == 0xffffffffuL) &&
  1048.                  (intel16( up->dstPort ) == s->myport )) break;
  1049.     }
  1050. #endif
  1051.     if (_dbugrecv) (*_dbugrecv)( (sock_type*)s, ip, up, 0);  // R. Whitby
  1052.     if ( !s ) {
  1053.         // S. Lawson - return ICMP port unreachable on non-broadcast
  1054.         if (my_ip_addr && temp!=0xffffffffuL && (~temp & ~sin_mask)) {
  1055. #ifdef DEBUG
  1056.            if (debug_on) outs("nrUDP: Discarding Packetnr");
  1057. #endif
  1058.            icmp_Unreach(ip);
  1059.         }
  1060.         return;
  1061.     }
  1062.     // these parameters are used for things other than just checksums
  1063.     ph.src = ip->source;    /* already INTELled */
  1064.     ph.dst = ip->destination;
  1065.     ph.mbz = 0;
  1066.     ph.protocol = UDP_PROTO;
  1067.     ph.length = up->length;
  1068.     if ( up->checksum ) {
  1069.         ph.checksum =  checksum(up, len);
  1070.         if (checksum(&ph, sizeof( tcp_PseudoHeader)) != 0xffff)
  1071.             return;
  1072.     }
  1073.     /* process user data */
  1074.     /* 2000.11.15 save first received packet rather than latest */
  1075.     if (( (len -= UDP_LENGTH ) > 0) && ( s->rdatalen == 0 )) {
  1076.         dp = (byte *)( up );
  1077.         if (s->dataHandler) s->dataHandler( s, &dp[ UDP_LENGTH ], len , &ph, up);
  1078.         else {
  1079.             if (len > s->maxrdatalen ) len = s->maxrdatalen;
  1080.             movmem( &dp[ UDP_LENGTH ], s->rdata, len );
  1081.             s->rdatalen = len;
  1082.         }
  1083.     }
  1084. }
  1085. static void tcp_handler( in_Header *ip )
  1086. {
  1087.     tcp_Header *tp;
  1088.     tcp_PseudoHeader ph;
  1089.     int len;
  1090. /*    byte *dp;  */
  1091.     int diff;
  1092.     tcp_Socket *s;
  1093.     word flags;
  1094.     long diffticks, ldiff;      /* must be signed */
  1095.     long scheduleto;
  1096.     if ( (longword)(intel( ip->destination ) - my_ip_addr) > multihomes )
  1097.         return;
  1098. #ifdef UNUSED   // S. Lawson - len wiped by 3rd line down anyway!
  1099.     len = in_GetHdrlenBytes(ip);
  1100.     len = intel16( ip->length ) - len;          /* len of tcp data */
  1101. #endif
  1102.     len = in_GetHdrlenBytes(ip);
  1103.     tp = (tcp_Header *)((byte *)ip + len);      /* tcp frame pointer */
  1104.     len = intel16( ip->length ) - len;          /* len of tcp data */
  1105.     flags = intel16( tp->flags );
  1106. #ifdef DEBUG
  1107.     if (debug_on > 1) {
  1108.             mono[160]++;
  1109.             colour[160]++;
  1110.             mono[162] = colour[162] = (flags & tcp_FlagSYN) ? 'S' : ' ';
  1111.             mono[164] = colour[164] = (flags & tcp_FlagACK) ? 'A' : ' ';
  1112.             mono[166] = colour[166] = (flags & tcp_FlagFIN) ? 'F' : ' ';
  1113.             mono[168] = colour[168] = (flags & tcp_FlagRST) ? 'R' : ' ';
  1114.         }
  1115. #endif
  1116.     /* demux to active sockets */
  1117.     for ( s = tcp_allsocs; s; s = s->next )
  1118.     {
  1119. #ifdef DEBUG
  1120.                 if ( s->safetysig != SAFETYTCP )
  1121.                 {
  1122.                 if (debug_on) outs("nrTCP: Chain Errornr");   // R. Whitby
  1123.                 }
  1124. #endif
  1125.                 if ( s->hisport != 0 &&
  1126.                      intel16( tp->dstPort ) == s->myport &&
  1127.                      intel16( tp->srcPort ) == s->hisport &&
  1128.                      intel( ip->destination )   == s->myaddr     &&
  1129.                      intel( ip->source ) == s->hisaddr ) break;
  1130.         }
  1131.         if ( !s && (flags & tcp_FlagSYN))
  1132.         {
  1133. /* demux to passive sockets, must be a new session */
  1134.                 for ( s = tcp_allsocs; s; s = s->next )
  1135.                     if ((s->hisport == 0) && (intel16( tp->dstPort ) == s->myport ))
  1136.                     {
  1137.                                 s->myaddr = intel( ip->destination );
  1138.                                 break;
  1139.                 }
  1140.     }
  1141.     if (_dbugrecv) (*_dbugrecv)( (sock_type*)s, ip, tp, 0 );
  1142.     if ( !s )
  1143.     {
  1144.                 if (!(flags & tcp_FlagRST)) tcp_rst( ip, tp );
  1145. //printf("tcp was resetn");
  1146.                 return;
  1147.     }
  1148.     ph.src = ip->source;        /* already INTELled */
  1149.     ph.dst = ip->destination;
  1150.     ph.mbz = 0;
  1151.     ph.protocol = TCP_PROTO;
  1152.     ph.length = intel16( len );
  1153.     ph.checksum =  checksum(tp, len);
  1154.     if ( checksum(&ph, sizeof(ph)) != 0xffff )
  1155.     {
  1156. #ifdef DEBUG
  1157.                  if (debug_on) outs("nrTCP: Bad Checksumnr");  // R. Whitby
  1158. #endif
  1159.                  tcp_sendsoon( s );
  1160.                  return;
  1161.     }
  1162. /* reset code */
  1163.     if ( flags & tcp_FlagRST ) {
  1164. #ifdef DEBUG
  1165.                 if (debug_on) outs("nrTCP: Connection Resetnr");  // R. Whitby
  1166. #endif
  1167.                 s->datalen = 0;
  1168.                 if (s->state != tcp_StateCLOSED && s->state != tcp_StateLASTACK)
  1169.                    s->rdatalen = 0;
  1170.                 s->err_msg = "Remote reset connection";
  1171.                 s->state = tcp_StateCLOSED;
  1172. /*      if (s->dataHandler) s->dataHandler(s, 0, -1); */
  1173.                 tcp_unthread(s);
  1174.         /* 2001.1.18 - make it fail tcp_tick() */
  1175.         s->ip_type = 0;
  1176.                 return;
  1177.     }
  1178.     if ( sock_inactive )
  1179.         s->inactive_to = set_timeout( sock_inactive );
  1180.     /* update our retransmission stuff */
  1181.     /* new algorithms */
  1182.     if (s->karn_count == 2) {
  1183.         s->karn_count = 0;
  1184. #ifdef DEBUG
  1185.         if (debug_on > 1 ) printf("finally got it safely zapped from %u to ????nr",s->unacked);
  1186. #endif /* DEBUG */
  1187.     } else {
  1188.         if ( s->vj_last ) {
  1189.             /* unnecessary to use unhappy || s->datalen ) */
  1190.             if ((diffticks = set_ttimeout( 0 ) - s->vj_last) >= 0 ) {
  1191.                 /* we ignore the overnight case */
  1192.                 diffticks -= (longword)( s->vj_sa >> 3 );
  1193.                 s->vj_sa += (int)diffticks;
  1194.                 if (diffticks < 0)
  1195.                     diffticks = - diffticks;
  1196.                 diffticks -= (s->vj_sd >> 2);
  1197.                 s->vj_sd += (int)diffticks;
  1198.                 if (s->vj_sa > MAXVJSA) s->vj_sa = MAXVJSA;
  1199.                 if (s->vj_sd > MAXVJSD) s->vj_sd = MAXVJSD;
  1200.             }
  1201.             /* only recompute rtt hence rto after success */
  1202.             s->rto = (1 + ((s->vj_sa >> 2) + (s->vj_sd))) >> 1 ;
  1203. #ifdef DEBUG
  1204.             if (debug_on > 1 ) printf("rto  %u  sa  %u  sd  %u   cwindow %u  wwindow %u  unacked %un",
  1205.                 s->rto, s->vj_sa, s->vj_sd, s->cwindow, s->wwindow, s->unacked );
  1206. #endif /* DEBUG */
  1207.         }
  1208.         s->karn_count = 0;
  1209.         if ( s->wwindow != 255 ) {
  1210.             if ( s->wwindow++ >= s->cwindow ) {
  1211.                 if ( s->cwindow != 255 )
  1212.                     s->cwindow ++;
  1213.       /* tcpwinfix
  1214.        *    Movement of the next line *seems* to fix the failure of the TCP
  1215.        *    send window to open up (which makes TCP writes very slow, as
  1216.        *    seen with some previous releases of WatFTP), though it's been
  1217.        *    a long time since I made this change (today is 96.09.24) and
  1218.        *    I'm not sure how confident I was even then that it was correct.
  1219.        *    Also I don't have any description of the VJ algorithm and don't
  1220.        *    really understand this code all that well, but some time ago
  1221.        *    this seemed to be the right thing to do and seems to work.
  1222.        *    That said, if I'm wrong, I hope I haven't broken things worse :-)
  1223.        *    There is one other place, also marked 'tcpwinfix' above in this
  1224.        *    file, and those are the only two changes I made for this bug
  1225.        *    which may need undoing if I'm wrong. -- mdurkin
  1226.        */
  1227.                 s->wwindow = 0;  /* mdurkin -- added 95.05.02 */
  1228.             }
  1229. /*            s->wwindow = 0;    /* mdurkin -- removed 95.05.02 */
  1230.         }
  1231.     }
  1232.     /* all new */
  1233.     scheduleto = set_ttimeout( s->rto + 2 );
  1234.     if ( s->rtt_time < scheduleto ) s->rtt_time = scheduleto;
  1235.     s->datatimer = 0;   /* EE 99.08.23 */
  1236.     s->gotflush = flags & tcp_FlagPUSH;  /* EE 2002.2.28 */
  1237.     switch ( s->state ) {
  1238.         case tcp_StateLISTEN:   /* accepting SYNs */
  1239.             /* save his ethernet address */
  1240.             if ( _pktipofs )
  1241.                 movmem(&((((eth_Header *)ip) - 1)->source), &s->hisethaddr, sizeof(eth_address));
  1242.             if ( flags & tcp_FlagSYN ) {
  1243.                 if ( ip->tos > s->tos )
  1244.                     s->tos = ip->tos;
  1245.                 else if ( ip->tos < s->tos ) {
  1246.                     /* RFC 793 says we should close connection */
  1247.                     /* we best not do that while SunOS ignores TOS */
  1248.                 }
  1249.                 s->acknum = intel( tp->seqnum ) + 1;
  1250.                 s->hisport = intel16( tp->srcPort );
  1251.                 s->hisaddr = intel( ip->source );
  1252.                 s->flags = tcp_FlagSYN | tcp_FlagACK;
  1253.                 s->state = tcp_StateSYNREC;
  1254.                 s->unhappy = true;
  1255.                 tcp_send(s, __LINE__);    /* we must respond immediately */
  1256.                 s->timeout = set_timeout( tcp_TIMEOUT );
  1257.             } else
  1258.                 tcp_rst( ip , tp );  /* send a reset */
  1259.             return;
  1260.     case tcp_StateSYNSENT:  /* added ACK Section */
  1261.             if ( flags & tcp_FlagSYN ) {
  1262.                 if ( ip->tos > s->tos )
  1263.                     s->tos = ip->tos;
  1264.                 else if ( ip->tos < s->tos ) {
  1265.                     /* RFC 793 says we should close connection */
  1266.                     /* we best not do that while SunOS ignores TOS */
  1267.                 }
  1268.                 s->flags = tcp_FlagACK;
  1269.                 s->timeout = set_timeout( tcp_TIMEOUT );
  1270.                 /* FlagACK means connection established, else SYNREC */
  1271.                 if ( flags & tcp_FlagACK) {
  1272.                     /* but is it for the correct session ? */
  1273.                 if (tp->acknum == intel(s->seqnum + 1)) {
  1274.                 s->state = tcp_StateESTAB;
  1275.                 s->seqnum++;    /* good increment */
  1276.                 s->acknum = intel( tp->seqnum  ) + 1;   /* 32 bits */
  1277.                 tcp_ProcessData(s, tp, len, &ph, &flags);    /* someone may try it */ /* S. Lawson */
  1278.                 s->unhappy = true;             /* rely on their attempts */
  1279.                 tcp_send( s, __LINE__ );
  1280.             } else {
  1281.                 /* wrong ack, force a RST and resend SYN soon*/
  1282.                 s->flags = tcp_FlagRST;
  1283.                 s->unhappy = true;
  1284.                 tcp_send( s, __LINE__ );
  1285.                 s->flags = tcp_FlagSYN;
  1286.                 tcp_send( s, __LINE__ );
  1287.                     }
  1288.                 } else {
  1289.                     s->acknum++;
  1290.                     s->state = tcp_StateSYNREC;
  1291.                     return;
  1292.                 }
  1293.             } else
  1294.                 tcp_rst( ip, tp );
  1295.             break;
  1296.         case tcp_StateSYNREC:   /* recSYNSENT, sentACK, waiting  EST */
  1297.             if ( flags & tcp_FlagSYN ) {
  1298.                 s->flags = tcp_FlagSYN | tcp_FlagACK;
  1299.                 s->unhappy = true;
  1300.                 tcp_send(s, __LINE__);
  1301.                 s->timeout = set_timeout( tcp_TIMEOUT );
  1302.                 return;
  1303.             }
  1304.             if ( (flags & tcp_FlagACK) && (intel( tp->acknum ) == (s->seqnum + 1))) {
  1305.                 if ( (s->window = intel16( tp->window )) > 0x7fff )
  1306.                     s->window = 0x7fff;
  1307.                 s->flags = tcp_FlagACK;
  1308.                 s->state = tcp_StateESTAB;
  1309.                 s->seqnum++;
  1310.                 s->timeout = 0;     /* never timeout */
  1311.                 s->unhappy = false;
  1312.                 return;
  1313.             }
  1314.             break;
  1315.         case tcp_StateESTAB:
  1316.         case tcp_StateESTCL:
  1317.         case tcp_StateCLOSWT:
  1318.             /* handle lost SYN */
  1319.             if ((flags & tcp_FlagSYN) && (flags & tcp_FlagACK)) {
  1320.                 tcp_send( s, __LINE__ );
  1321.                 return;
  1322.             }
  1323.             if ( !(flags & tcp_FlagACK)) return;  /* must ack somthing */
  1324. #ifdef NOTUSED  // S. Lawson - above two IFs make this impossible
  1325.             if ( flags & tcp_FlagSYN ) {
  1326.                 tcp_rst( ip , tp );
  1327.                 return;
  1328.             }
  1329. #endif
  1330.             s->timeout = 0l;    /* we do not timeout at this point */
  1331.             /* process ack value in packet - but only if it falls
  1332.              * within current window */
  1333.             ldiff = intel( tp->acknum ) - s->seqnum;
  1334.             diff = (int) ldiff;
  1335.             if ( ldiff >= 0 && diff <= s->datalen ) {
  1336.                 s->datalen -= diff;
  1337.                 s->unacked -= diff;
  1338.                 if (s->datalen < 0) s->datalen = 0; /* remote proto error */
  1339.                 if ( s->queuelen ) {
  1340.                     s->queue += diff;
  1341.                     s->queuelen -= diff;
  1342.                 } else
  1343.                     movmem(s->data + diff, s->data, s->datalen );
  1344.                 s->seqnum += ldiff;
  1345.             } else {
  1346. #ifdef DEBUG
  1347.     if(debug_on >1) printf("tcphandler confused so set unacked back to 0 from %un",s->unacked);
  1348. #endif// DEBUG
  1349.                 s->unacked = 0;
  1350.             }
  1351.             if (s->unacked < 0) s->unacked = 0;
  1352.             s->flags = tcp_FlagACK;
  1353.             tcp_ProcessData(s, tp, len, &ph, &flags);   // S. Lawson
  1354. #ifdef NOTUSED
  1355.         // S. Lawson - this chokes on some stacks. (data+fin) comes in, the
  1356.         // FIN isn't ACK'd and they resend the whole segment rather than
  1357.         // just the FIN (getting us back to not ACKing FIN on (data+fin)
  1358.             if (( flags & tcp_FlagFIN ) && (s->state != tcp_StateCLOSWT )
  1359.                 && ( s->acknum == intel( tp->seqnum ))) {
  1360. #else
  1361.             if (( flags & tcp_FlagFIN ) && (s->state != tcp_StateCLOSWT )
  1362.                 && s->frag[0]==0L) {
  1363. #endif
  1364.                 s->acknum ++;
  1365.                 if ( ! s->err_msg ) s->err_msg = "Connection closed";
  1366.                 s->state = tcp_StateCLOSWT;
  1367.                 tcp_send( s, __LINE__ );
  1368.                 s->timeout = set_timeout( LASTACK_TIMEOUT );    // Added AGW 6 Jan 2001
  1369.                 s->state = tcp_StateLASTACK;
  1370.                 s->flags |= tcp_FlagFIN;
  1371.                 s->unhappy = true;
  1372.             }
  1373. /* S. Lawson - added per below
  1374.  *   Eliminate the spurious ACK messages bug.
  1375.  *   For the window update, the length should be the
  1376.  *   data length only, so exclude the TCP header size
  1377.  *    -- Joe <jdhagen@itis.com> (this helped alot -gv)
  1378.  */
  1379.             len -= tcp_GetDataOffset(tp) << 2;
  1380. // S. Lawson - don't send on ACK unless there's more to send
  1381. //          if ( diff > 0 || len > 0 ) {
  1382.             if ( (diff > 0 && s->datalen) || len > 0 ) {   // S. Lawson
  1383.                 /* need to update window, but how urgent ??? */
  1384. // S. Lawson            if ( diff > 0 || (len > (s->mss >> 1))) {
  1385.                 if (s->frag[0] || (diff > 0 && s->datalen) || (len > (s->mss >> 1))) { // S. Lawson
  1386.                     tcp_send( s, __LINE__ );
  1387.                 } else
  1388.                     tcp_sendsoon( s );
  1389.             }
  1390.             if ( s->state == tcp_StateESTCL )
  1391.                 tcp_close( s );
  1392.             return;
  1393.         case tcp_StateFINWT1:
  1394.             /* They have not necessarily read all the data yet, we must
  1395.                still supply it as requested */
  1396.             ldiff = intel( tp->acknum ) - s->seqnum;
  1397.             diff = (int) ldiff;
  1398.             if ( ldiff >= 0 && diff <= s->datalen ) {
  1399.                 s->datalen -= diff;
  1400.                 s->unacked -= diff;
  1401.                 if (s->datalen < 0) s->datalen = 0;
  1402.                 if ( s->queuelen ) {
  1403.                     s->queue += diff;
  1404.                     s->queuelen -= diff;
  1405.                 } else
  1406.                     movmem(s->data + diff, s->data, s->datalen );
  1407.                 s->seqnum += ldiff;
  1408.                 if (ldiff == 0 || s->unacked < 0) s->unacked = 0;
  1409.             }
  1410.             /* they may still be transmitting data, we must read it */
  1411.             tcp_ProcessData(s, tp, len, &ph, &flags);   // S. Lawson
  1412.             /* check if other tcp has acked all sent data and is ready
  1413.                to change states */
  1414. // S. Lawson        if ( (flags & (tcp_FlagFIN|tcp_FlagACK) ) == (tcp_FlagFIN|tcp_FlagACK)) {
  1415.             if ( s->frag[0]==0L && (flags & (tcp_FlagFIN|tcp_FlagACK) ) ==
  1416.                  (tcp_FlagFIN|tcp_FlagACK)) {           // S. Lawson
  1417. #ifdef NOTUSED  // S. Lawson - below is untrue, misses a condition, and moves
  1418.                 //             to the wrong state anyway
  1419.                 /* trying to do similtaneous close */
  1420.                 if (( intel( tp->acknum ) >= s->seqnum + 1 ) &&
  1421.                     ( intel( tp->seqnum) == s->acknum )) {
  1422.                     s->seqnum++;
  1423. // we shouldn't be inc'ing the ack
  1424. //                  s->acknum++;
  1425.                     s->flags = tcp_FlagACK;
  1426.                     tcp_send( s, __LINE__ );
  1427.                     s->unhappy = false;
  1428.                     s->timeout = set_timeout( 2 );
  1429.                     s->state = tcp_StateCLOSED;
  1430.                 }
  1431. #else
  1432.                 if ( intel( tp->seqnum) == s->acknum ) {
  1433.                     word next_state;
  1434.                     s->acknum++;                // we must ACK their FIN!
  1435.                     if (( intel( tp->acknum ) >= s->seqnum + 1 )) {
  1436.                         // Not simultaneous close (they've ACKed our FIN)
  1437.                         // We need to ACK their FIN and move to TIME_WAIT
  1438.                         s->seqnum++;
  1439.                         next_state=tcp_StateTIMEWT;
  1440.                     } else {
  1441.                         // Simultaneous close (haven't ACKed our FIN yet)
  1442.                         // We need to ACK their FIN and move to CLOSING
  1443.                         next_state=tcp_StateCLOSING;
  1444.                     }
  1445.                     s->flags = tcp_FlagACK;
  1446.                     tcp_send( s, __LINE__ );
  1447.                     s->unhappy = false;
  1448.                     if ((s->state = next_state) == tcp_StateTIMEWT)
  1449.                         s->timeout = set_timeout( TW_TO );
  1450.                     else
  1451.                         s->timeout = set_timeout( tcp_TIMEOUT );
  1452.                 }
  1453. #endif
  1454.             } else if ( flags & tcp_FlagACK ) {
  1455.                 /* other side is legitimately acking our fin */
  1456.                 if (( intel( tp->acknum ) == s->seqnum + 1 ) &&
  1457.                     ( intel( tp->seqnum ) == s->acknum ) &&
  1458.                     (  s->datalen == 0 )) {
  1459.                         s->seqnum++;
  1460. // they are just acking our seq num, not sending more data for us to ack
  1461. //                      s->acknum++;
  1462.                         s->state = tcp_StateFINWT2;
  1463.                         s->timeout = set_timeout( tcp_TIMEOUT );  // S. Lawson
  1464.                         s->unhappy = false; /* we don't send anything */
  1465.                 }
  1466.             }
  1467.             break;
  1468.         case tcp_StateFINWT2:
  1469.             /* they may still be transmitting data, we must read it */
  1470.             tcp_ProcessData(s, tp, len, &ph, &flags);           // S. Lawson
  1471.             if (s->frag[0] != 0L) break;        // S. Lawson
  1472.             if ((flags & (tcp_FlagACK | tcp_FlagFIN)) ==
  1473.                   (tcp_FlagACK | tcp_FlagFIN)) {
  1474.                 if (( intel( tp->acknum ) == s->seqnum) &&
  1475.                     ( intel( tp->seqnum ) == s->acknum )) {
  1476.                     s->acknum++;
  1477.                     s->flags = tcp_FlagACK;
  1478.                     tcp_send( s, __LINE__ );
  1479.                     s->unhappy = false; /* we don't send anything */
  1480. #ifdef NOTUSED  // S. Lawson - move to TIME_WAIT, not CLOSED
  1481.                     s->timeout = set_timeout( 2 );
  1482.                     s->state = tcp_StateCLOSED;
  1483. #else
  1484.                     s->timeout = set_timeout( TW_TO );
  1485.                     s->state = tcp_StateTIMEWT;
  1486. #endif
  1487.                     return;
  1488.                 }
  1489.             }
  1490.             break;
  1491.         case tcp_StateCLOSING:
  1492.             if ((flags & (tcp_FlagACK | tcp_FlagFIN)) == tcp_FlagACK ) {
  1493. // S. Lawson - per FINWT1 above, tcp->acknum should be s->seqnum+1, which
  1494. //             we should cause us to bump s->seqnum to match
  1495. //              if (( tp->acknum == intel(s->seqnum) ) &&
  1496. //AGW           if (( tp->acknum >= (intel(s->seqnum) + 1) ) &&  // S. Lawson
  1497.                 if ((laterthan(intel(tp->acknum),s->seqnum) ) && //AGW - moved intel() so +1 OK 6th Jan 2001
  1498.                     ( tp->seqnum == intel(s->acknum))) {
  1499.                     s->seqnum++;                                 // S. Lawson
  1500.                     s->state = tcp_StateTIMEWT;
  1501.                     s->timeout = set_timeout( TW_TO );
  1502.                     s->unhappy = false;
  1503.                 }
  1504.             }
  1505.             break;
  1506.         case tcp_StateLASTACK:
  1507.             if ( flags & tcp_FlagFIN )
  1508.             {   /* they lost our two packets, back up */
  1509.                         s->flags = tcp_FlagACK | tcp_FlagFIN;
  1510.                         tcp_send( s, __LINE__ );
  1511.                         s->unhappy = TRUE;  /* FALSE; */
  1512.                         return;
  1513.             } else
  1514.             {
  1515. //                      if (( intel( tp->acknum ) == (s->seqnum + 1 )) &&
  1516.                         if ((laterthan(intel(tp->acknum),s->seqnum) ) &&        // AGW allow for any later acks 6th Jan 2001
  1517.                             ( intel( tp->seqnum ) == s->acknum ))
  1518.                         {
  1519.                                 s->state = tcp_StateCLOSED;     /* no 2msl necessary */
  1520.                                 s->unhappy = false;             /* we're done */
  1521.                                 return;
  1522.                     }
  1523.             }
  1524.             break;
  1525.         case tcp_StateTIMEWT:
  1526.             if ( (flags & (tcp_FlagACK | tcp_FlagFIN)) == (tcp_FlagACK | tcp_FlagFIN)) {
  1527.                 /* he needs an ack */
  1528.                 s->flags = tcp_FlagACK;
  1529.                 tcp_send( s, __LINE__ );
  1530.                 s->unhappy = false;
  1531.                 s->state = tcp_StateCLOSED;     /* support 2 msl in rst code */
  1532.             }
  1533.             break;
  1534.         }
  1535.     if (s->unhappy) tcp_sendsoon(s);
  1536. }
  1537. /*
  1538.  * Process the data in an incoming packet.
  1539.  * Called from all states where incoming data can be received: established,
  1540.  * fin-wait-1, fin-wait-2
  1541.  * S. Lawson - added flagsp so we can disable FIN with segment(s) missing
  1542.  */
  1543. static void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len,
  1544.                             tcp_PseudoHeader *ph, word *flagsp)
  1545. {
  1546.     long ldiff, tmpldiff;               // S. Lawson
  1547.     int diff, tmpdiff, x;               // S. Lawson
  1548.     word flags;
  1549.     byte *dp;
  1550. // S. Lawson    word *options, numoptions, opt_temp;
  1551.     byte *options;                      // S. Lawson
  1552.     word numoptions, opt_temp;          // S. Lawson
  1553.     if ( s->stress > 0 ) s->stress--;
  1554.     if ( (s->window = intel16( tp->window )) > 0x7fff )
  1555.         s->window = 0x7fff;
  1556.     flags = intel16( tp->flags );
  1557.     ldiff = s->acknum - intel( tp->seqnum );
  1558.     if ( flags & tcp_FlagSYN ) ldiff--;  /* back up to 0 */
  1559.     diff = abs((int) ldiff);            // S. Lawson - make positive
  1560.     /* find the data portion */
  1561.     x = tcp_GetDataOffset(tp) << 2;     /* quadword to byte format */
  1562.     dp = (byte *)tp + x;
  1563.     /* process those options */
  1564.     if ( (numoptions = x - sizeof( tcp_Header )) != 0 ) {
  1565. // S. Lawson    options = (word *)((byte *)(tp) + sizeof( tcp_Header));
  1566.         options = ((byte *)(tp) + sizeof( tcp_Header)); // S. Lawson
  1567.         while ( numoptions-- > 0 ) {
  1568.             switch ( *options++ ) {
  1569.                 case  0 : numoptions = 0;       /* end of options */
  1570.                           break;
  1571.                 case  1 : break;                /* nop */
  1572.                           /* we are very liberal on MSS stuff */
  1573. // S. Lawson - this is broken, *options includes type/len bytes
  1574. //              case  2 : if (*options == 2) {
  1575.                 case  2 : if (*options == 4) {
  1576.                               opt_temp = intel16( *(word*)(&options[1]));
  1577.                               if (opt_temp < s->mss )
  1578.                                   s->mss = opt_temp;
  1579.                           }
  1580. #ifdef NOTUSED  // S. Lawson - this is broken, *options includes type/len
  1581.                           numoptions -= 2 + *options;
  1582.                           options += *options;
  1583.                           break;
  1584. #else
  1585.                 // S. Lawson - fallthrough (case 2),
  1586.                 //             also skips unknown options (thanks GV)
  1587.                 default:                // S. Lawson - handle 2 and others
  1588.                           numoptions -= (*options - 1);
  1589.                           options += (*options - 1);
  1590.                           break;
  1591. #endif
  1592.             }
  1593.         }
  1594.     }
  1595.     /* done option processing */
  1596.     len -= x;           /* remove the header length */
  1597.     if ( ldiff >= 0 ) {  /* skip already received bytes */
  1598.         dp += diff;
  1599.         len -= diff;
  1600.         if (s->dataHandler) {
  1601.             s->acknum += s->dataHandler(s, dp, len, ph, tp);  // 94.11.19
  1602. //          s->acknum += s->dataHandler(s, dp, len);
  1603.         } else {
  1604.             /* no handler, just dump to buffer, should be indexed, handles goofs */
  1605.             /* limit receive size to our window */
  1606.             if ( s->rdatalen >= 0 ) {
  1607.                 if ( len > ( x = s->maxrdatalen - s->rdatalen )) {
  1608.                     len = x;
  1609.                 }
  1610.                 // S. Lawson - no writing into fragment
  1611.                 if (s->frag[0] != 0L) {
  1612.                     tmpldiff=s->frag[0] - s->acknum;
  1613.                     tmpdiff= abs((int) tmpldiff);
  1614.                     if (tmpldiff>=0 && len>tmpdiff) len=tmpdiff;
  1615.                 }
  1616.                 if ( len > 0 ) {
  1617.                     s->acknum += len;   /* our new ack begins at end of data */
  1618.                     movmem(dp, s->rdata + s->rdatalen, len );
  1619.                     s->rdatalen += len;
  1620. /*
  1621.                     s->karn_count = 3;
  1622. */
  1623.                 }
  1624.                 // S. Lawson - see if we reached fragment
  1625.                 if (s->frag[0] != 0L) {
  1626.                     if (s->frag[0]==s->acknum) {
  1627.                        tmpldiff=s->frag[1] - s->acknum;
  1628.                        tmpdiff=abs((int) tmpldiff);
  1629.                        if (tmpldiff>0) {
  1630.                           s->rdatalen += tmpdiff;
  1631.                           s->acknum=s->frag[1];
  1632.                        }
  1633.                        s->frag[0]=s->frag[1]=0L;
  1634.                     }
  1635.                 }
  1636.             }
  1637.         }
  1638.         s->unhappy = (s->datalen) ? true : false;
  1639.         if (ldiff == 0 && s->unacked && chk_timeout( s->rtt_lasttran )) {
  1640. #ifdef DEBUG
  1641.             if(debug_on >1) printf("data process timeout so set unacked back to 0 from %un",s->unacked);
  1642. #endif// DEBUG
  1643.             s->unacked = 0;
  1644.         }
  1645.     } else {
  1646.         // S. Lawson - no out-of-sequence processing of FIN flag
  1647.         *flagsp &= ~tcp_FlagFIN;
  1648.         // S. Lawson - handle one dropped segment
  1649.         if (s->frag[0]==0L) {           // just dropped a segment
  1650.            len=min(s->maxrdatalen - s->rdatalen - diff, len);
  1651.            if (len > 0) {
  1652.               movmem(dp, s->rdata + s->rdatalen + diff, len );
  1653.               s->frag[0]=s->frag[1]=intel(tp->seqnum);
  1654.               s->frag[1]+=len;
  1655.            }
  1656.         } else {                        // haven't seen missing segment yet
  1657.            tmpldiff=s->frag[0]-intel(tp->seqnum);
  1658.            tmpdiff=abs((int) tmpldiff);
  1659.            if (tmpldiff>0 && len>=tmpdiff) { // prepend bytes touching fragment
  1660.               movmem(dp, s->rdata + s->rdatalen + diff, tmpdiff );
  1661.               s->frag[0]-=tmpdiff;
  1662.            }
  1663.            tmpldiff=(intel(tp->seqnum)+len) - s->frag[1];
  1664.            tmpdiff=abs((int) tmpldiff);
  1665.            if (tmpldiff>0) {            // append bytes touching fragment
  1666.               int src,dst;
  1667.               tmpldiff=s->frag[1] - intel(tp->seqnum);
  1668.               if (tmpldiff>=0) {
  1669.                  src=abs((int) tmpldiff);                      // packet source offset
  1670.                  tmpldiff=s->frag[1] - s->acknum;
  1671.                  dst=abs((int) tmpldiff);                      // buffer destination offset
  1672.                  tmpdiff=min(s->maxrdatalen-s->rdatalen-dst,tmpdiff); // length to move
  1673.                  if (tmpdiff > 0) {
  1674.                     movmem(dp+src , s->rdata+s->rdatalen+dst, tmpdiff );
  1675.                     s->frag[1]+=tmpdiff;
  1676.                  }
  1677.               }
  1678.            }
  1679.         }
  1680. // S. Lawson    tcp_sendsoon( s );
  1681.     }
  1682. // S. Lawson - remove per GV (interferes with callers setting)
  1683. //    s->timeout = set_timeout( tcp_TIMEOUT );
  1684.     return;
  1685. }
  1686. /*
  1687.  * Format and send an outgoing segment
  1688.  */
  1689. static void tcp_send( tcp_Socket *s, int line )
  1690. {
  1691.     tcp_PseudoHeader ph;
  1692.     struct _pkt {
  1693.         in_Header in;
  1694.         tcp_Header tcp;
  1695.         word maxsegopt[2];
  1696.     } *pkt;
  1697.     byte *dp;
  1698.     in_Header *inp;
  1699.     tcp_Header *tcpp;
  1700.     int senddatalen, sendtotlen, sendpktlen, startdata, sendtotdata;
  1701.     int ippkt;          /* 1..s->cwindow */
  1702.     s->recent = 0;
  1703.     pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr, /*0x800*/ 8);
  1704.     dp = (byte *) &pkt->maxsegopt;  /* dp constant for multi-packet sends */
  1705.     inp = &pkt->in;
  1706.     tcpp = &pkt->tcp;
  1707.     /* this is our total possible send size */
  1708.     if ( s->karn_count != 2 ) {
  1709.         /* BUG FIX : jason dent found this */
  1710.         // S. Lawson - (so did Morten Terstrup <MorTer@dk-online.dk>)
  1711. /*      sendtotdata = min( s->datalen - s->unacked, s->window );  */
  1712.         // S. Lawson - then a sign problem with the fix was found by
  1713.         // (Morten Terstrup, Lumetech A/S, Denmark. 970414)
  1714.         //   bug: Since window is unsigned, should unacked be greater the
  1715.         //        subtraction will create a large positive for max().  This
  1716.         //        will become a negative number in the signed sendtotdata.
  1717.         //   fix: max must be evaluated after the senttotdata assignment
  1718.         //        (S. Lawson - a cast alone should do it but gets messy)
  1719. //      sendtotdata = max (min ( s->datalen, s->window ) - s->unacked, 0);
  1720.         sendtotdata = (int)(min( s->datalen, s->window ) - s->unacked);
  1721.         if (sendtotdata<0) sendtotdata=0;
  1722.         startdata = s->unacked;
  1723.     } else {
  1724.         sendtotdata = (s->datalen >= s->window)? s->window : s->datalen;
  1725.         startdata = 0;
  1726.     }
  1727. /*
  1728.     if (sendtotdata < 0) sendtotdata = 0;
  1729. */
  1730.     sendtotlen = 0;     /* running count of what we've sent */
  1731.     /* step through our packets */
  1732.     for ( ippkt = 1; ippkt <= s->cwindow; ++ippkt ) {
  1733.         /* adjust size for each packet */
  1734.         senddatalen = min( sendtotdata, s->mss );
  1735.     /*
  1736.         sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
  1737.         inp->length = intel16( sendpktlen );
  1738.     */
  1739.         /* tcp header */
  1740.         tcpp->srcPort = intel16( s->myport );
  1741.         tcpp->dstPort = intel16( s->hisport );
  1742.         tcpp->seqnum = intel( s->seqnum + startdata ); /* unacked - no longer sendtotlen */
  1743.         tcpp->acknum = intel( s->acknum );
  1744.         tcpp->window = intel16( s->maxrdatalen - s->rdatalen );
  1745.         tcpp->flags = intel16( s->flags | 0x5000 );
  1746.         tcpp->checksum = 0;
  1747.         tcpp->urgentPointer = 0;
  1748.         /* do options if this is our first packet */
  1749.         if ( s->flags & tcp_FlagSYN ) {
  1750.             sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header ) + 4;
  1751.             tcpp->flags = intel16( intel16( tcpp->flags) + 0x1000 );
  1752.             pkt->maxsegopt[0] = 0x0402;
  1753.             pkt->maxsegopt[1] = intel16( s->mss );
  1754.             dp += 4;
  1755.         } else {
  1756.             /* handle packets with data */
  1757.             if (senddatalen > 0) {
  1758.                 sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
  1759.                 /* get data from appropriate place */
  1760.                 if (s->queuelen) movmem(s->queue + startdata, dp, senddatalen );
  1761.                 else movmem(s->data + startdata, dp, senddatalen);
  1762. /*                dp[ senddatalen ] = 0; */
  1763.             } else {
  1764.             /* handle no-data, not-first-SYN packets */
  1765.                 sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header );
  1766.             }
  1767.         }
  1768.         /* internet header */
  1769.         memset( inp, 0, sizeof( in_Header ));
  1770.         inp->ver = 4;
  1771.         inp->hdrlen = 5;
  1772.         inp->tos = s->tos;
  1773.         inp->identification = intel16( ++ip_id );   /* was post inc */
  1774. //        inp->frag = 0;
  1775.         inp->ttl = 254;
  1776.         inp->proto = TCP_PROTO;
  1777.         inp->checksum = 0;
  1778.         inp->source = intel( s->myaddr );
  1779.         inp->destination = intel( s->hisaddr );
  1780.         inp->length = intel16( sendpktlen );
  1781.         inp->checksum = ~checksum( inp, sizeof(in_Header));
  1782.         /* compute tcp checksum */
  1783.         ph.src = inp->source;   /* already INTELled */
  1784.         ph.dst = inp->destination;
  1785.         ph.mbz = 0;
  1786.         ph.protocol = 6;
  1787.         ph.length = intel16( sendpktlen - sizeof(in_Header));
  1788. /*
  1789.         ph.checksum = checksum(&pkt->tcp, (sendpktlen - sizeof(in_Header) +1) & 0xfffe);
  1790. */
  1791.         ph.checksum = checksum(&pkt->tcp, sendpktlen - sizeof(in_Header));
  1792.         tcpp->checksum = ~checksum(&ph, sizeof(ph));
  1793.         if (_dbugxmit) (*_dbugxmit)( (sock_type *)s, inp, tcpp, line );
  1794. #ifdef DEBUG
  1795.         if (debug_on > 1) {
  1796.             mono[0]++;
  1797.             colour[0]++;
  1798.             mono[2] = colour[2] = (s->flags & tcp_FlagSYN) ? 'S' : ' ';
  1799.             mono[4] = colour[4] = (s->flags & tcp_FlagACK) ? 'A' : ' ';
  1800.             mono[6] = colour[6] = (s->flags & tcp_FlagFIN) ? 'F' : ' ';
  1801.             mono[8] = colour[8] = (s->flags & tcp_FlagRST) ? 'R' : ' ';
  1802.         }
  1803. #endif
  1804. /*
  1805. if(gone_bad && gone_bad==s)
  1806. {
  1807. printf("sending: ack=%lu,seq=%lun",intel(tcpp->acknum),intel(tcpp->seqnum));
  1808. }
  1809. */
  1810.         if ( _eth_send( intel16( inp->length ))) { /* encounterred error */
  1811.             tcp_sendsoon( s );
  1812.             return;
  1813.         }
  1814.         /* do next ip pkt */
  1815.         sendtotlen += senddatalen;
  1816.         startdata += senddatalen;
  1817.         sendtotdata -= senddatalen;
  1818.         if (sendtotdata <= 0 ) break;
  1819.     }
  1820.     s->unacked = startdata;
  1821. #ifdef DEBUG
  1822. if (debug_on)
  1823.         printf(" Sent %u/%u bytes in %u/%u packets  with (%u) unacked  SEQ %lu  line %un",
  1824.         sendtotlen, s->window, (ippkt-1), s->cwindow, s->unacked, s->seqnum, line);
  1825. #endif // DEBUG
  1826.     s->vj_last = 0;
  1827.     if ( s->karn_count == 2 ) {
  1828.         if (s->rto) s->rto = (s->rto * 3) / 2;
  1829.         else s->rto = 4;
  1830.     } else {
  1831.         /* vj_last nonzero if we expect an immediate response */
  1832.         if (s->unhappy || s->datalen)
  1833.             s->vj_last = set_ttimeout( 0 );
  1834.         s->karn_count = 0;
  1835.     }
  1836.     s->rtt_time = set_ttimeout( s->rto + 2 );
  1837.     if (sendtotlen > 0 ) s->rtt_lasttran =  s->rtt_time + s->rto;
  1838. }
  1839. /*
  1840.  * Format and send a reset tcp packet
  1841.  */
  1842. static void tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp )
  1843. {
  1844.     tcp_PseudoHeader ph;
  1845.     struct _pkt {
  1846.         in_Header in;
  1847.         tcp_Header tcp;
  1848.         word maxsegopt[2];
  1849.     } *pkt;   /*, *his_pkt; */
  1850.     static longword nextrst = 0L;
  1851.     word oldflags;
  1852.     in_Header *inp;
  1853.     tcp_Header *tcpp;
  1854.     eth_Header *eth;
  1855.     int sendtotlen;     /* length of packet */
  1856.     int temp;
  1857. #ifdef NEVER
  1858.     longword templong;
  1859. #endif
  1860.     /* see RFC 793 page 65 for details */
  1861.     if ( !chk_timeout( nextrst )) return;
  1862.     nextrst = set_ttimeout( 1 );
  1863.     oldflags = intel16( oldtcpp->flags );
  1864.     if (oldflags & tcp_FlagRST ) return;
  1865. #ifdef NEVER
  1866.     if ( (oldflags & (tcp_FlagACK | tcp_FlagFIN)) == (tcp_FlagACK | tcp_FlagFIN) ){
  1867.         templong = oldtcpp->seqnum;
  1868.         oldtcpp->seqnum = oldtcpp->acknum;
  1869.         oldtcpp->acknum = templong;
  1870.         oldflags = tcp_FlagACK;
  1871.     } else if ((oldflags & (tcp_FlagSYN | tcp_FlagACK)) ==  tcp_FlagSYN ) {
  1872.         oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + 1 );
  1873.         oldtcpp->seqnum = 0;
  1874.         oldflags = tcp_FlagACK | tcp_FlagRST;
  1875.     } else if ( oldflags & tcp_FlagACK ) {
  1876.         oldtcpp->seqnum = oldtcpp->acknum;
  1877.         oldtcpp->acknum = 0;
  1878.     } else {
  1879.         oldtcpp->acknum = intel( intel(oldtcpp->seqnum) + 1);
  1880.         oldtcpp->seqnum = 0;
  1881.     }
  1882.     if ( oldflags & ( tcp_FlagFIN | tcp_FlagSYN ) == 0 )
  1883.         oldflags ^= tcp_FlagACK | tcp_FlagRST;
  1884.     if ( oldflags & tcp_FlagACK ) {
  1885.         oldtcpp->seqnum = oldtcpp->acknum;
  1886. #else
  1887.     /* better strategy - Dean Roth */
  1888.     if ( oldflags & tcp_FlagACK ) {
  1889.         oldtcpp->seqnum = oldtcpp->acknum;
  1890.         oldtcpp->acknum = 0;
  1891.         oldflags = tcp_FlagRST;
  1892.     } else if ((oldflags & (tcp_FlagSYN | tcp_FlagACK)) ==  tcp_FlagSYN ) {
  1893.         oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + 1 );
  1894.         oldtcpp->seqnum = 0;
  1895.         oldflags = tcp_FlagACK | tcp_FlagRST;
  1896.     } else {
  1897.         temp = intel16( his_ip->length) - in_GetHdrlenBytes( his_ip );
  1898.         oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + temp );
  1899.         oldtcpp->seqnum = 0;
  1900.         oldflags = tcp_FlagRST;
  1901.     }
  1902. #endif
  1903. /* 94.11.19 -- removed, not used? */
  1904. /*    his_pkt  = (struct _pkt*)( his_ip );  */
  1905.     /* convoluted mechanism - reads his ethernet address or garbage */
  1906.     eth = _eth_hardware( (byte *)his_ip );
  1907.     pkt = (struct _pkt *)_eth_formatpacket( (eth_address *)eth, 8);
  1908.     inp = &pkt->in;
  1909.     tcpp = &pkt->tcp;
  1910.     sendtotlen = sizeof( tcp_Header ) + sizeof( in_Header );
  1911.     memset( inp, 0, sizeof( in_Header ));
  1912.     inp->length = intel16( sendtotlen );
  1913.     /* tcp header */
  1914.     tcpp->srcPort = oldtcpp->dstPort;
  1915.     tcpp->dstPort = oldtcpp->srcPort;
  1916.     tcpp->seqnum = oldtcpp->seqnum;
  1917.     tcpp->acknum = oldtcpp->acknum;
  1918.     tcpp->window = 0;
  1919. /*    tcpp->flags = intel16( oldflags ); */
  1920.     /* BUG FIX : jason dent found this thanks to SCO */
  1921.     tcpp->flags = intel16( (oldflags & 0x0fff ) | 0x5000 );
  1922.     tcpp->checksum = 0;
  1923.     tcpp->urgentPointer = 0;
  1924.     /* internet header */
  1925.     inp->ver = 4;
  1926.     inp->hdrlen = 5;
  1927.     inp->tos = his_ip->tos;
  1928.     inp->identification = intel16( ++ip_id );
  1929. //    inp->frag = 0;
  1930.     inp->ttl = 254;
  1931.     inp->proto = TCP_PROTO;
  1932.     inp->checksum = 0;
  1933.     inp->source = his_ip->destination;
  1934.     inp->destination = his_ip->source;
  1935.     inp->checksum = ~checksum( inp, sizeof(in_Header))/* 0*/;
  1936.     /* compute tcp checksum */
  1937.     ph.src = inp->source;       /* already INTELled */
  1938.     ph.dst = inp->destination;
  1939.     ph.mbz = 0;
  1940.     ph.protocol = 6;
  1941.     ph.length = intel16( sendtotlen - sizeof(in_Header));
  1942.     ph.checksum = checksum(&pkt->tcp, sizeof(tcp_Header));
  1943.     tcpp->checksum =  ~checksum(&ph, sizeof(ph));
  1944.     if (_dbugxmit) (*_dbugxmit)(NULL,inp,tcpp,__LINE__);
  1945.     _eth_send( intel16( inp->length ));
  1946. }
  1947. /**********************************************************************
  1948.  * socket functions
  1949.  **********************************************************************/
  1950. /* socket based stuff */
  1951. /*
  1952.  * sock_read - read a socket with maximum n bytes
  1953.  *           - busywaits until buffer is full but calls s->usr_yield
  1954.  *           - returns count also when connection gets closed
  1955.  */
  1956. int sock_read( sock_type *s, byte *dp, int len )
  1957. {
  1958.     int templen, count;
  1959.     count = 0;
  1960.     do {
  1961.         if ( s->udp.ip_type == UDP_PROTO )
  1962.             templen = udp_read( &(s->udp), dp, len );
  1963.         else
  1964.             templen = tcp_read( &(s->tcp), dp, len);
  1965.         if (s->tcp.usr_yield) (s->tcp.usr_yield)();
  1966.         if (templen < 1 ) {
  1967.             if (!tcp_tick( s )) return( count );
  1968.         } else {
  1969.             count += templen;
  1970.             dp += templen;
  1971.             len -= templen;
  1972.         }
  1973.         /* 99.07.01 EE */
  1974.         if ( len > 0 && s->tcp.usr_yield)
  1975.             (s->tcp.usr_yield)();
  1976.     } while ( len );
  1977.     return( count );
  1978. }
  1979. /*
  1980.  * sock_fead - read a socket with maximum n bytes
  1981.  *           - does not busywait until buffer is full
  1982.  */
  1983. int sock_fastread( sock_type *s, byte *dp, int len )
  1984. {
  1985.     if ( s->udp.ip_type == UDP_PROTO )
  1986.         len = udp_read( &(s->udp), dp, len );
  1987.     else
  1988.         len = tcp_read( &(s->tcp), dp, len);
  1989.     return( len );
  1990. }
  1991. /*
  1992.  * sock_write - writes data and returns length written
  1993.  *            - does not perform flush
  1994.  *            - repeatedly calls s->usr_yield
  1995.  */
  1996. int sock_write( sock_type *s, byte *dp, int len )
  1997. {
  1998.     int offset, oldlen, oldmode, proto;
  1999.     oldlen = len;
  2000.     offset = 0;
  2001. #ifdef NOTUSED    /* EE 99.06.14 */
  2002.     proto = (s->udp.ip_type == TCP_PROTO);
  2003.     if ( proto ) oldmode = s->tcp.flags & tcp_FlagPUSH;
  2004. #else             /* EE 99.06.14 */
  2005.     proto = s->udp.ip_type;
  2006.     if ( proto == 0 ) return( 0 );
  2007.     if ( proto == TCP_PROTO ) oldmode = s->tcp.flags & tcp_FlagPUSH;
  2008. #endif            /* EE 99.06.14 */
  2009.     while ( len  > 0) {
  2010. /* EE 99.06.14  if (proto) { */
  2011.         if (proto == TCP_PROTO ) {      /* EE 99.06.14 */
  2012.             s->tcp.flags |= oldmode;
  2013.             offset += tcp_write( &(s->tcp), &dp[ offset ], len);
  2014.         } else
  2015.             offset += udp_write( &(s->udp), &dp[ offset ], len, offset );
  2016.         len = oldlen - offset;
  2017.         if ( len > 0 )                  /* EE 99.7.2 */
  2018.             if (s->udp.usr_yield)(s->udp.usr_yield)();
  2019.         if (!tcp_tick(s)) return( 0 );
  2020.     }
  2021.     return( oldlen );
  2022. }
  2023. /* NOTE: for UDP, assumes data fits in one datagram, else only the first
  2024.        fragment will be sent!!!!!  Because _mss is used for splits,
  2025.        by default the max data size is 1400 - UDP_LENGTH for a non-fragged
  2026.        datagram.
  2027.  */
  2028. int sock_fastwrite( sock_type *s, byte *dp, int len )
  2029. {
  2030. #ifdef NOTUSED  /* EE 99.06.14 */
  2031.     return( ( s->udp.ip_type == UDP_PROTO ) ?
  2032.         udp_write( &(s->udp), dp, len, 0 ) :
  2033.         tcp_write( &(s->tcp), dp, len) );
  2034. #else           /* EE 99.06.14 */
  2035.     switch ( s->udp.ip_type ) {
  2036.         case UDP_PROTO : return( udp_write( &(s->udp), dp, len, 0 ));
  2037.         case TCP_PROTO : return( tcp_write( &(s->tcp), dp, len) );
  2038.         default : return( 0 );
  2039.     }
  2040. #endif          /* EE 99.06.14 */
  2041. }
  2042. int sock_setbuf( sock_type *s, byte *dp, int len )
  2043. {
  2044.     if ( len < 0 ) return( 0 );
  2045.     if (len == 0 || dp == NULL ) {
  2046.         s->tcp.rdata = s->tcp.rddata;
  2047.         s->tcp.maxrdatalen = tcp_MaxBufSize;
  2048.     } else {
  2049.         s->tcp.rdata = dp;
  2050.         s->tcp.maxrdatalen = len;
  2051.     }
  2052.     return( s->tcp.maxrdatalen);
  2053. }
  2054. int sock_enqueue( sock_type *s, byte *dp, int len )
  2055. {
  2056.     int written;
  2057.     word offset = 0;
  2058.     if ( len < 0 ) return( 0 );
  2059.     if ( s->udp.ip_type == UDP_PROTO ) {
  2060.         do {
  2061.             written = udp_write( &(s->udp), dp, len, offset );
  2062.             dp += written;
  2063.             offset += written;
  2064.         } while (len -= written > 0);
  2065.     } else {
  2066.         s->tcp.queue = dp;
  2067.         s->tcp.queuelen = len;
  2068.         s->tcp.datalen = len;
  2069.         tcp_send( &(s->tcp), __LINE__ );  /* start sending it */
  2070.     }
  2071.     return( len );
  2072. }
  2073. void sock_noflush( sock_type *s )
  2074. {
  2075.     if ( s->tcp.ip_type == TCP_PROTO ) {
  2076.         s->tcp.flags &= ~tcp_FlagPUSH;
  2077.         s->tcp.sock_mode |= TCP_LOCAL ;
  2078.     }
  2079. }
  2080. void sock_flush( sock_type *s )
  2081. {
  2082.     if ( s->tcp.ip_type == TCP_PROTO ) {
  2083.         s->tcp.sock_mode &= ~TCP_LOCAL;
  2084.         tcp_Flush( &(s->tcp) );
  2085.     }
  2086. }
  2087. /*
  2088.  * sock_flushnext - cause next transmission to have a flush
  2089.  */
  2090. void sock_flushnext( sock_type *s)
  2091. {
  2092.     if (s->tcp.ip_type == TCP_PROTO ) {
  2093.         s->tcp.flags |= tcp_FlagPUSH;
  2094.         s->tcp.sock_mode &= ~TCP_LOCAL;
  2095.     }
  2096. }
  2097. /*
  2098.  * sock_putc - put a character
  2099.  *           - no expansion but flushes on 'n'
  2100.  *           - returns character
  2101.  */
  2102. byte sock_putc( sock_type *s, byte c )
  2103. {
  2104.     if (( c == 'n') || ( c == 'r'))
  2105.         sock_flushnext( s );
  2106.     sock_write( s, &c, 1 );
  2107.     return( c );
  2108. }
  2109. int sock_getc( sock_type *s )
  2110. {
  2111.     byte ch;
  2112.     return( sock_read( s, &ch, 1 ) < 1 ? EOF : ch );
  2113. }
  2114. /*
  2115.  * sock_puts - does not append carriage return in binary mode
  2116.  *           - returns length
  2117.  */
  2118. int sock_puts( sock_type *s, byte *dp )
  2119. {
  2120.     int len;   /*, oldmode;*/
  2121.     len = strlen( (char *)dp );
  2122.     if (s->tcp.sock_mode & TCP_MODE_ASCII ) {
  2123.         sock_noflush( s );
  2124.         if (len) sock_write( s, dp, len );
  2125.         sock_flushnext( s );
  2126.         sock_write( s, (byte *)"rn", 2 );
  2127.     } else {
  2128.         sock_flushnext( s );
  2129.         sock_write( s, dp, len );
  2130.     }
  2131.     return( len );
  2132. }
  2133. /*
  2134.  * sock_update - update the socket window size to the other guy
  2135.  */
  2136. static void sock_update( tcp_Socket *s )
  2137. {
  2138. // S. Lawson    if (s->ip_type == TCP_PROTO) {
  2139.     if (s->ip_type == TCP_PROTO && s->state != tcp_StateCLOSED) {  // S. Lawson
  2140.         if ( !s->rdatalen )
  2141.             tcp_send( s, __LINE__ );              /* update the window */
  2142.         else
  2143.             tcp_sendsoon( s );
  2144.     }
  2145. }
  2146. #ifdef NOTUSED                                  // R. Whitby
  2147. /*
  2148.  * sock_gets - read a string from any socket
  2149.  *           - return length of returned string
  2150.  *           - removes end of line terminator(s)
  2151.  *
  2152.  *           - Quentin Smart fixed some problems
  2153.  */
  2154. int sock_gets( sock_type *s, byte *dp, int n )
  2155. {
  2156.     int len, *np;
  2157.     byte *src_p, *temp, *temp2;
  2158.     if ( s->udp.ip_type == UDP_PROTO ) {
  2159.         src_p = s->udp.rdata;
  2160.         np = &s->udp.rdatalen;
  2161.     } else {
  2162.         src_p = s->tcp.rdata;
  2163.         np = &s->tcp.rdatalen;
  2164.     }
  2165.     if ( *np == 0 ) return( 0 );
  2166.     // eat trailing n or  from previous line
  2167.     if ( *src_p == 0 || *src_p == 'n' ) {
  2168.         movmem( src_p + 1, src_p, *np -= 1 );
  2169.         if ( !*np ) return( 0 );
  2170.     }
  2171.     if ( --n > *np ) n = *np;
  2172.     // Q.Smart found and fixed a bug here
  2173.     memcpy( dp, src_p, n );     // copy everything
  2174.     dp[ n ] = 0;                // terminate new string
  2175.     temp = memchr( dp, 'n', n);
  2176.     temp2= memchr( dp, 'r', n);
  2177.     if (temp)  *temp = 0;
  2178.     if (temp2) *temp2= 0;
  2179.     // skip if there were no crs
  2180.     if ( !temp2 ) {
  2181.         *dp = 0;
  2182.         return( 0 );
  2183.     }
  2184. //  not: len = strlen( dp );
  2185.     len = (int)(( temp ? min( FP_OFF(temp), FP_OFF(temp2)) :
  2186.         FP_OFF(temp2)) - FP_OFF(dp));
  2187.     // expect rn or r or n or r
  2188.     // so get first of the two
  2189.     if ( temp == NULL ) {       /* handles r only */
  2190.         temp = temp2;
  2191.         temp2 = NULL;
  2192.     } else if ( FP_OFF( temp ) > FP_OFF( temp2 ))
  2193.         temp = temp2;           // handles trailing n or 
  2194.     n = len + 1;                // account for first r
  2195.     // we check next char if it exists, and skip it if 0, r, or n
  2196.     if ((*np > n) && !src_p[n] ) n++;
  2197.     movmem( &src_p[ n ], src_p, *np -= n );
  2198.     if (*np < 0) *np = 0;
  2199.     sock_update( &(s->tcp) );   /* new window */
  2200.     return( len );
  2201. }
  2202. #else                                           // R. Whitby
  2203. /*
  2204.  * sock_gets - read a string from any socket
  2205.  *           - return length of returned string
  2206.  *           - removes end of line terminator(s)
  2207.  */
  2208. int sock_gets( sock_type *s, byte *dp, int n )
  2209. {
  2210.     int len, rmax, *np, frag;
  2211.     byte *src_p, *nl_p, *cr_p;
  2212.     /* Access the buffer pointer and length. */
  2213.     if ( s->udp.ip_type == UDP_PROTO ) {
  2214.         src_p = s->udp.rdata;
  2215.         np = &s->udp.rdatalen;
  2216.         rmax = (int) s->udp.maxrdatalen;
  2217.         frag=0;
  2218.     } else {
  2219.         src_p = s->tcp.rdata;
  2220.         np = &s->tcp.rdatalen;
  2221.         rmax = (int) s->tcp.maxrdatalen;
  2222.         frag=0;
  2223.         if (s->tcp.frag[0] != 0L) {
  2224.            long ldiff=s->tcp.frag[1] - s->tcp.acknum;
  2225.            frag=abs((int) ldiff);
  2226.         }
  2227.         if ((s->tcp.sock_mode & TCP_SAWCR)) {
  2228.             s->tcp.sock_mode &= ~TCP_SAWCR;
  2229.             if (*np && (*src_p == 'n' || *src_p == ''))
  2230.                 movmem( src_p + 1, src_p, frag+((*np)--));
  2231.         }
  2232.     }
  2233.     /* Return if there is nothing in the buffer. */
  2234.     if ( *np == 0 ) return( 0 );
  2235.     /* If there is space for all the data, then copy all of it,
  2236.        otherwise, only copy what the space will allow (taking
  2237.        care to reserve space for the null terminator. */
  2238.     if ( --n > *np ) n = *np;
  2239.     memcpy( dp, src_p, n );     // copy everything
  2240.     dp[ n ] = 0;                // terminate new string
  2241.     /* At this point, dp is a null-terminated string,
  2242.        containing as much of the data as is possible. */
  2243.     len = n;
  2244.     /* Because we are in ASCII mode, we assume that the
  2245.        sender will be consistent in which kind of CRLF is
  2246.        sent (e.g. one and only one of rn, r0, r, or n).
  2247.        So if both r and n are found, we assume that they
  2248.        are always next to each other, and nr is invalid. */
  2249.     /* Zero the first occurance of r and n in dp. */
  2250.     cr_p = memchr( dp, 'r', n); if (cr_p) *cr_p = 0;
  2251.     nl_p = memchr( dp, 'n', n); if (nl_p) *nl_p = 0;
  2252.     /* handle flushed end of strings EE 02.02.28 */
  2253.     if ( s->tcp.ip_type == TCP_PROTO ) {
  2254.         if ( s->tcp.gotflush) {
  2255.             if ( !cr_p ) {
  2256.                 cr_p = dp + n;
  2257.                 s->tcp.gotflush = 0;
  2258.             }
  2259.         }
  2260.     }
  2261.     /* Return if we did not find r or n yet, but still had room. */
  2262.     // S. Lawson - *and* the connection can get more data!
  2263.     if ( !cr_p && !nl_p && (n >= *np) && (*np < rmax)
  2264.          && s->tcp.state != tcp_StateLASTACK
  2265.          && s->tcp.state != tcp_StateCLOSED ) {
  2266.       *dp = 0;
  2267.       return( 0 );
  2268.     }
  2269.     /* If we did find a terminator, then stop there. */
  2270.     if (cr_p || nl_p) {
  2271.       // Find the length of the first line of data in dp. */
  2272.       len = (int)
  2273.         (((nl_p && cr_p) ?
  2274.              min(FP_OFF(nl_p), FP_OFF(cr_p)) :
  2275.                (nl_p ? FP_OFF(nl_p) : FP_OFF(cr_p)))
  2276.          - FP_OFF(dp) );
  2277.       /* We found a terminator character ... */
  2278.       n = len + 1;
  2279.       /* If r at end of data, might get a  or n in next packet */
  2280.       if (cr_p && (*np == n))
  2281.          s->tcp.sock_mode |= TCP_SAWCR;
  2282.       /* ... and it could have been r or rn.*/
  2283.       if ((*np > n) &&
  2284.           (!src_p[n] || (cr_p && src_p[n] == 'n'))) n++;
  2285.     }
  2286.     /* Remove the first line from the buffer. */
  2287.     *np -= n;
  2288.     if (frag || *np > 0 ) movmem( &src_p[ n ], src_p, frag+(*np) );
  2289.     sock_update( &(s->tcp) );   /* new window */
  2290.     return( len );
  2291. }
  2292. #endif                                          // R. Whitby
  2293. /*
  2294.  * sock_dataready - returns number of bytes waiting to be ready
  2295.  *                - if in ASCII mode, return 0 until a line is present
  2296.  *                  or the buffer is full
  2297.  */
  2298. int sock_dataready( sock_type *s )
  2299. {
  2300.     int len;
  2301.     byte *p;
  2302.     if (!(len = s->tcp.rdatalen)) return( 0 );
  2303.     if ( s->tcp.sock_mode & TCP_MODE_ASCII ) {
  2304.         p = s->tcp.rdata;
  2305.         if ((s->tcp.sock_mode & TCP_SAWCR)) {           // S. Lawson
  2306.             s->tcp.sock_mode &= ~TCP_SAWCR;             // S. Lawson
  2307.             if ( *p == 'n' || *p == '') {            // S. Lawson
  2308.                 movmem( p + 1, p, s->tcp.rdatalen = --len);
  2309.                 if ( ! len ) return( 0 );
  2310.             }
  2311.         }
  2312.         // R. Whitby
  2313.         if ( len == s->tcp.maxrdatalen )
  2314.             return( len );
  2315.         /* EE 99.07.02 */
  2316.         if ( s->tcp.state == tcp_StateLASTACK )
  2317.             return( len );
  2318.         // S. Lawson - happens if final ACK arrives before app reads data
  2319.         if ( s->tcp.state == tcp_StateCLOSED )
  2320.             return( len );
  2321.         /* check for terminating r */
  2322.         if ( memchr( p, 'r', len))
  2323.             return( len );
  2324.         /* EE 99.04.30 */
  2325.         if ( memchr( p, 'n', len ))
  2326.             return( len );
  2327.         return( 0 );
  2328.     } else
  2329.         return( len );
  2330. }
  2331. int sock_established( sock_type *s )
  2332. {
  2333.     switch ( s->tcp.ip_type ) {
  2334.         case UDP_PROTO :
  2335.                 return( 1 );
  2336.         case TCP_PROTO :
  2337.                 return( s->tcp.state >= tcp_StateESTAB
  2338.                 /* changed 2000.7.31 by Erick Engelke */
  2339.                 /*      s->tcp.state == tcp_StateESTAB ||
  2340.                         s->tcp.state == tcp_StateESTCL ||
  2341.                         s->tcp.state == tcp_StateCLOSWT */ );
  2342.         default :
  2343.                 return( 0 );
  2344.     }
  2345. }
  2346. void sock_close( sock_type *s )
  2347. {
  2348.     switch (s->udp.ip_type) {
  2349.         case UDP_PROTO :
  2350.                 udp_close( &(s->udp) );
  2351.                 break;
  2352.         case TCP_PROTO :
  2353.                 tcp_close( &(s->tcp) );
  2354.                 tcp_tick( s );
  2355.                 break;
  2356.     }
  2357. }
  2358. void sock_sturdy( sock_type *s, int level )
  2359. {
  2360.     s->tcp.rigid = level;
  2361.     if ( s->tcp.rigid < s->tcp.stress ) sock_abort( s );
  2362. }
  2363. /*
  2364.  * _ip_delay0 called by macro sock_wait_established()
  2365.  * _ip_delay1 called by macro sock_wait_intput()
  2366.  * _ip_delay2 called by macro sock_wait_closed();
  2367.  *
  2368.  */
  2369. int _ip_delay0( sock_type *s, int timeoutseconds, sockfunct_t fn, int *statusptr )
  2370. {
  2371.     int status;
  2372.     ip_timer_init( s , timeoutseconds );
  2373.     do {
  2374.         if ( s->tcp.ip_type == TCP_PROTO ) {
  2375.             if ( tcp_established( &(s->tcp) )) {
  2376.                 status = 0;
  2377.                 break;
  2378.             }
  2379.         }
  2380.         kbhit();        /* permit ^c */
  2381.         if ( !tcp_tick( s )) {
  2382.              if (!s->tcp.err_msg) s->tcp.err_msg = "Host refused connection";
  2383.              status = -1;       /* get an early reset */
  2384.              break;
  2385.         }
  2386.         if ( ip_timer_expired( s )) {
  2387.             s->tcp.err_msg = "Open timed out";
  2388.             sock_close( s );
  2389.             status = -1;
  2390.             break;
  2391.         }
  2392.         if ( (fn != NULL) && ((status = fn(s)) != 0) ) break;
  2393.         if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2394.         if ( s->tcp.ip_type == UDP_PROTO ) {
  2395.             status = 0;
  2396.             break;
  2397.         }
  2398.     } while ( 1 );
  2399.     if (statusptr) *statusptr = status;
  2400.     return( status );
  2401. }
  2402. int _ip_delay1( sock_type *s, int timeoutseconds, sockfunct_t fn, int *statusptr)
  2403. {
  2404.     int status;
  2405.     ip_timer_init( s , timeoutseconds );
  2406.     sock_flush( s );    /* new enhancement */
  2407.     do {
  2408.         if ( sock_dataready( s )) {
  2409.             status = 0;
  2410.             break;
  2411.         }
  2412.         kbhit();        /* permit ^c */
  2413.         if ( !tcp_tick( s )) {
  2414.             status = 1;
  2415.             break;
  2416.         }
  2417.         if ( ip_timer_expired( s )) {
  2418.             s->tcp.err_msg = "Connection timed out";
  2419.             sock_close( s );
  2420.             status = -1;
  2421.             break;
  2422.         }
  2423.         if (fn) {
  2424.             if ((status = fn(s)) != 0)
  2425.                 break;
  2426.         }
  2427.         if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2428.     } while ( 1 );
  2429.     if (statusptr) *statusptr = status;
  2430.     return( status );
  2431. }
  2432. int _ip_delay2( sock_type *s, int timeoutseconds, sockfunct_t fn, int *statusptr)
  2433. {
  2434.     int status;
  2435.     ip_timer_init( s , timeoutseconds );
  2436.     if (s->tcp.ip_type != TCP_PROTO ) {
  2437.         if ( statusptr ) * statusptr = 1;
  2438.         return( 1 );
  2439.     }
  2440.     do {
  2441.         /* in this situation we KNOW user not planning to read rdata */
  2442.         s->tcp.rdatalen = 0;
  2443.         kbhit();        /* permit ^c */
  2444.         if ( !tcp_tick( s )) {
  2445.             status = 1;
  2446.             break;
  2447.         }
  2448.         if ( ip_timer_expired( s )) {
  2449.             s->tcp.err_msg = "Connection timed out";
  2450.             sock_abort( s );
  2451.             status = -1;
  2452.             break;
  2453.         }
  2454.         if (fn) {
  2455.             if ((status = fn(s)) != 0)
  2456.                 break;
  2457.         }
  2458.         if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2459.     } while ( 1 );
  2460.     if (statusptr) *statusptr = status;
  2461.     return( status );
  2462. }
  2463. char *rip( char *s )
  2464. {
  2465.     char *temp;
  2466.     if ((temp = strchr( s, 'n')) != NULL) *temp = '';
  2467.     if ((temp = strchr( s, 'r')) != NULL) *temp = '';
  2468.     return( s );
  2469. }