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

操作系统开发

开发平台:

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