home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / wattcp.zip / PCTCP.C < prev    next >
C/C++ Source or Header  |  1992-08-05  |  60KB  |  2,150 lines

  1. /* DEBUG flag may be set for my internal playing */
  2.  
  3. /*
  4. #define DEBUG
  5. */
  6.  
  7. /*
  8.  *  PCTCP - the true worker of Waterloo TCP
  9.  *         - contains all opens, closes, major read/write routines and
  10.  *        basic IP handler for incomming packets
  11.  *      - NOTE: much of the TCP/UDP/IP layering is done at the data structure
  12.  *        level, not in separate routines or tasks
  13.  *
  14.  */
  15.  
  16. #include <copyright.h>
  17. #include <time.h>
  18. #include <stdio.h>
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <mem.h>
  23. #include <dos.h>
  24. #include <values.h>
  25.  
  26. #include "wattcp.h"
  27. #include "elib.h"
  28.  
  29. #define TCP_LOCAL 0x4000
  30.  
  31. /* statics */
  32. static tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len);
  33.  
  34. static char far *mono = 0xb0000000L;
  35. static char far *colour = 0xb8000000L;
  36.  
  37. static initialized = 0;
  38. static void (*system_yield)() = NULL;
  39. extern int multihomes;
  40. void (*_dbugxmit)() = NULL;
  41. void (*_dbugrecv)() = NULL;
  42. void (*wattcpd)() = NULL;
  43.  
  44. char *_hostname = "012345678901234567890123456789012345678901234567890";
  45.  
  46. word _mss = ETH_MSS;
  47.  
  48. char *_wattcp = WATTCP_C;
  49.  
  50. /*
  51.  * sock_yield - enable user defined yield function
  52.  */
  53. sock_yield( tcp_Socket *s, void (*fn)())
  54. {
  55.     if ( s )
  56.     s->usr_yield = fn;
  57.     else
  58.     system_yield = fn;
  59. }
  60.  
  61. /*
  62.  * sock_mode - set binary or ascii - affects sock_gets, sock_dataready
  63.  *         - set udp checksums
  64.  */
  65. sock_mode( sock_type *s, word mode )
  66. {
  67.      s->tcp.sock_mode = (s->tcp.sock_mode & 0xfffc) | mode;
  68. }
  69.  
  70. /*
  71.  * ip user level timer stuff
  72.  *   void ip_timer_init( void *s, int delayseconds )
  73.  *   int  ip_timer_expired( void *s )
  74.  *    - 0 if not expired
  75.  */
  76. static unsigned long far *realclock = 0x000046cL;
  77. #define MAXTICKS 0x1800b0L
  78.  
  79. void ip_timer_init( s , delayseconds )
  80. udp_Socket *s;
  81. int delayseconds;
  82. {
  83.     if (delayseconds)
  84.     s->usertimer = set_timeout( delayseconds );
  85.     else
  86.     s->usertimer = 0;
  87. }
  88.  
  89. int ip_timer_expired( s )
  90. udp_Socket *s;
  91. {
  92.     if (! s->usertimer)    /* cannot expire */
  93.     return( 0 );
  94.     return( chk_timeout( s->usertimer));
  95. }
  96. longword MsecClock()
  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. /*
  106.  * check_timeout - test agains timeout clock - account for overflow
  107.  */
  108. static int check_timeout( unsigned long timeout )
  109. {
  110.     if (timeout) return( chk_timeout( timeout ));
  111.     return( 0 );
  112. }
  113.  
  114. /*
  115.  * Local IP address
  116.  */
  117. longword my_ip_addr = 0L;    /* for external references */
  118. longword sin_mask = 0xfffffe00L;
  119. longword sin_gate = 0x0;
  120.  
  121.  
  122. /*
  123.  * IP identification numbers
  124.  */
  125.  
  126. static int ip_id = 0;            /* packet number */
  127. static int next_tcp_port = 1024;    /* auto incremented */
  128. static int next_udp_port = 1024;
  129. static tcp_Socket *tcp_allsocs = NULL;
  130. static udp_Socket *udp_allsocs = NULL;
  131.  
  132. /* Timer definitions */
  133. #define RETRAN_STRAT_TIME  1     /* in ticks - how often do we check retransmitter tables*/
  134. #define tcp_RETRANSMITTIME 3     /* interval at which retransmitter is called */
  135. #define tcp_LONGTIMEOUT 31       /* timeout for opens */
  136. #define tcp_TIMEOUT 13           /* timeout during a connection */
  137.  
  138. word debug_on = 0;
  139.  
  140. /*
  141.  * look for bugs
  142.  */
  143. tcp_checkfor( tcp_Socket *t )
  144. {
  145.     tcp_Socket *p;
  146.  
  147.     for ( p = tcp_allsocs ; p ; p = p->next )
  148.         if ( p == t ) return( 1 );
  149.     return( 0 );
  150. }
  151.  
  152. /*
  153.  * Shut down the card and all services
  154.  */
  155. tcp_shutdown()
  156. {
  157.     while (tcp_allsocs)
  158.     tcp_abort( tcp_allsocs );
  159.     _eth_release();
  160.     initialized = 0;
  161. }
  162.  
  163. /*
  164.  * tcp_Init - Initialize the tcp implementation
  165.  *        - may be called more than once without hurting
  166.  */
  167. tcp_init()
  168. {
  169.     extern int _arp_last_gateway;
  170.     extern int _last_nameserver;
  171.  
  172.     if (!initialized) {
  173.     /* initialize ethernet interface */
  174.     initialized = 1;
  175.     _eth_init();
  176.  
  177.     /* reset the various tables */
  178.     _arp_last_gateway = 0;    /* reset the gateway table */
  179.     _last_nameserver = 0;    /* reset the nameserver table */
  180.     _last_cookie = 0;    /* eat all remaining crumbs */
  181.     *_hostname = 0;        /* reset the host's name */
  182.  
  183.     if (!my_ip_addr) {
  184.         /* using our local reverse ethernet address thingamajig */
  185.         movmem( &_eth_addr[2], &my_ip_addr, 4 );
  186.     }
  187.     _eth_free( 0 );
  188.     next_udp_port = next_tcp_port = 1024 + ((*realclock >> 7 )& 0x1ff);
  189.     }
  190. }
  191.  
  192. /*
  193.  * Checks for bugs in large model C compiler
  194.  */
  195. static largecheck( void *s, int size )
  196. {
  197. #ifdef __TURBOC__
  198.     if ( (word)(FP_OFF(s)) > (word)(-size)) {
  199.         outs("ERROR: user stack size error\n");
  200.         exit( 3 );
  201.     }
  202. #endif
  203. }
  204.  
  205. /*
  206.  * findfreeport - return unused local port
  207.  *              - we need not be this picky, but it doesn't hurt
  208.  */
  209. static word findfreeport()
  210. {
  211.     word temp;
  212.     tcp_Socket *s;
  213.  
  214.     temp = (word) set_timeout( 0 ) + (word)(set_timeout(0) >> 16);
  215.  
  216.     do {
  217.         if ( ++temp < 1024 ) temp += 1024;
  218.         if ( s = (tcp_Socket*)udp_allsocs ) {
  219.             while ( s->next && (s->myport != temp))
  220.                 s = (tcp_Socket*)s->next;
  221.             if ( s->myport == temp ) continue;
  222.         }
  223.         if ( s = tcp_allsocs ) {
  224.             while ( s->next && (s->myport != temp ))
  225.                 s = s->next;
  226.             if ( s->myport == temp ) continue;
  227.         }
  228.         break;
  229.     } while ( 1 );
  230.     return( temp );
  231. }
  232.  
  233. /* socket, localport, destaddress */
  234. int udp_open(s, lport, ina, port, datahandler)
  235. udp_Socket *s;
  236. longword ina;
  237. word lport, port;
  238. procref datahandler;
  239. {
  240.     udp_close( s );
  241.     largecheck( s, sizeof( udp_Socket ));
  242.     memset( s, 0, sizeof( udp_Socket ));
  243.     s->rdata = s->rddata;
  244.     s->maxrdatalen = tcp_MaxBufSize;
  245.     s->ip_type = UDP_PROTO;
  246.     if ( lport == 0 ) lport = findfreeport();  /* get a nonzero port val */
  247.     s->myport = lport;
  248.     s->myaddr = my_ip_addr;
  249.  
  250.     /* check for broadcast */
  251.     if ( (long)(ina) == -1 || !ina )
  252.     memset( s->hisethaddr, 0xff, sizeof( eth_address ));
  253.     else if ( ! _arp_resolve(ina, &s->hisethaddr[0]) )
  254.     return( 0 );
  255.  
  256.     s->hisaddr = ina;
  257.     s->hisport = port;
  258.     s->dataHandler = datahandler;
  259.     s->usr_yield = system_yield;
  260.     s->safetysig = SAFETYUDP;
  261.     s->next = udp_allsocs;
  262.     udp_allsocs = s;
  263.     return( 1 );
  264. }
  265.  
  266. /*
  267.  * Actively open a TCP connection to a particular destination.
  268.  *    - 0 on error
  269.  */
  270. int tcp_open(tcp_Socket *s, word lport, longword ina, word port, procref datahandler)
  271. {
  272.     largecheck( s, sizeof( tcp_Socket ));   /* stack space warnings */
  273.     tcp_unthread(s);                        /* just in case not totally closed */
  274.  
  275.     memset( s, 0, sizeof( tcp_Socket));
  276.     s->rdata = s->rddata;
  277.     s->maxrdatalen = tcp_MaxBufSize;
  278.     s->ip_type = TCP_PROTO;
  279.     s->mss = _mss;
  280.     s->state = tcp_StateSYNSENT;
  281.     s->timeout = set_timeout( tcp_LONGTIMEOUT );
  282.     s->cwindow = 1;
  283.     s->wwindow = 0;     /* slow start VJ algorithm */
  284.     s->vj_sa = 4;      /* about 250 ms */
  285.     if ( lport == 0 ) lport = findfreeport();  /* get a nonzero port val */
  286.     s->myaddr = my_ip_addr;
  287.     s->myport = lport;
  288.     if ( ! _arp_resolve(ina, &s->hisethaddr[0]) )
  289.     return( 0 );
  290.  
  291.     s->hisaddr = ina;
  292.     s->hisport = port;
  293.     s->seqnum = intel( set_timeout( 1 )) & 0xffff0000;
  294.     s->datalen = 0;
  295.     s->flags = tcp_FlagSYN;
  296.     s->unhappy = true;
  297.     s->dataHandler = datahandler;
  298.     s->usr_yield = system_yield;
  299.  
  300.     s->safetysig = SAFETYTCP;       /* insert into chain */
  301.     s->next = tcp_allsocs;
  302.     tcp_allsocs = s;
  303.  
  304.     s->rtt_delay = s->rtt_smooth = 18;    /* one second startup */
  305.     tcp_send(s, __LINE__ );
  306.     return( 1 );
  307. }
  308.  
  309. /*
  310.  * Passive open: listen for a connection on a particular port
  311.  */
  312. tcp_listen(tcp_Socket *s, word lport, longword ina, word port, procref datahandler, word timeout)
  313. {
  314.     largecheck( s, sizeof( tcp_Socket ));
  315.     tcp_unthread(s);                        /* just in case not totally closed */
  316.     memset( s, 0, sizeof( tcp_Socket));
  317.     s->rdata = s->rddata;
  318.     s->maxrdatalen = tcp_MaxBufSize;
  319.     s->ip_type = TCP_PROTO;
  320.     s->mss = _mss;
  321.     s->cwindow = 1;
  322.     s->wwindow = 0;     /* slow start VJ algorithm */
  323.     s->vj_sa = 36;      /* about 250 ms */
  324.  
  325.     s->state = tcp_StateLISTEN;
  326.     if ( !timeout ) s->timeout = 0; /* forever... */
  327.     else s->timeout = set_timeout( timeout );
  328.     if ( lport == 0 ) lport = findfreeport();  /* get a nonzero port val */
  329.     s->myport = lport;
  330.     s->hisport = port;
  331.     s->hisaddr = ina;
  332.     s->seqnum = intel( (word)(s));
  333.     s->datalen = 0;
  334.     s->flags = 0;
  335.     s->unhappy = false;
  336.     s->dataHandler = datahandler;
  337.     s->usr_yield = system_yield;
  338.  
  339.     s->safetysig = SAFETYTCP;       /* insert into chain */
  340.     s->next = tcp_allsocs;
  341.     tcp_allsocs = s;
  342.  
  343.     return( 1 );
  344. }
  345.  
  346.  
  347. static udp_close(ds)
  348. udp_Socket *ds;
  349. {
  350.     udp_Socket *s, **sp;
  351.  
  352.     sp = &udp_allsocs;
  353.     for (;;) {
  354.         s = *sp;
  355.         if ( s == ds ) {
  356.             *sp = s->next;
  357.             break;
  358.         }
  359.     if ( !s ) break;
  360.     if ( ! s->err_msg ) s->err_msg = "UDP Close called";
  361.     sp = &s->next;
  362.     }
  363. }
  364.  
  365. /*
  366.  * Send a FIN on a particular port -- only works if it is open
  367.  *   Must still allow receives
  368.  */
  369. static tcp_close(tcp_Socket *s)
  370. {
  371.     if ( s->ip_type != TCP_PROTO )
  372.     return;
  373.     if ( s->state == tcp_StateESTAB ||
  374.          s->state == tcp_StateESTCL ||
  375.          s->state == tcp_StateSYNREC ) {
  376.  
  377.         if ( s->datalen ) {     /* must first flush all data */
  378.             s->flags |= tcp_FlagPUSH | tcp_FlagACK;
  379.             if ( s->state < tcp_StateESTCL ) {
  380.                 s->state = tcp_StateESTCL;
  381.                 tcp_sendsoon( s );
  382.             }
  383.         } else { /* really closing */
  384.             s->flags = tcp_FlagACK | tcp_FlagFIN;
  385.             if (!s->err_msg)
  386.                 s->err_msg = "Connection closed normally";
  387.             s->state = tcp_StateFINWT1;
  388.             s->timeout = set_timeout( 4 ); /* should be a pretty lengthy time */
  389.             tcp_send( s, __LINE__ );
  390.         }
  391.         s->unhappy = true;
  392.     } else if (s->state == tcp_StateCLOSWT ) {
  393.         /* need to ack the fin and get on with it */
  394.         s->state = tcp_StateLASTACK;
  395.         s->flags |= tcp_FlagFIN;
  396.         tcp_send( s, __LINE__ );
  397.         s->unhappy = true;
  398.     }
  399. }
  400.  
  401. /*
  402.  * Abort a tcp connection
  403.  */
  404. static tcp_abort(tcp_Socket *s)
  405. {
  406.     if (!s->err_msg) s->err_msg = "TCP_ABORT";
  407.     if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
  408.         s->flags = tcp_FlagRST  | tcp_FlagACK ;
  409.         s->unhappy = true;
  410.         tcp_send(s, __LINE__);
  411.     }
  412.     s->unhappy = false;
  413.     s->datalen = 0;
  414.     s->ip_type = 0;
  415.     s->state = tcp_StateCLOSED;
  416. /*    if (s->dataHandler) s->dataHandler(s, 0, -1); */
  417.     tcp_unthread(s);
  418. }
  419.  
  420. void sock_abort(tcp_Socket *s )
  421. {
  422.     if ( s->ip_type == TCP_PROTO )
  423.     tcp_abort( s );
  424.     else
  425.     udp_close( s );
  426. }
  427. /*
  428.  * tcp_sendsoon - schedule a transmission pretty soon
  429.  *        - this one has an imperfection at midnight, but it
  430.  *          is not significant to the connection performance
  431.  */
  432. tcp_sendsoon(tcp_Socket *s )
  433. {
  434.     longword temp;
  435.     if (s->ip_type == TCP_PROTO ) {
  436.     temp = set_ttimeout( 1 );
  437.         if ( temp == s->rtt_time && s->rto < 2 && s->recent == 0 ) {
  438.             s->karn_count = 0;
  439.             tcp_send( s, __LINE__ );
  440.             s->recent = 1;
  441.             return;
  442.         }
  443.         if ((s->unhappy || s->datalen > 0 || s->karn_count == 1)
  444.           && (s->rtt_time < temp ))
  445.             return;
  446.  
  447.         s->rtt_time = set_ttimeout( 1 + (s->rto >> 4) );
  448.     s->karn_count = 1;
  449.     }
  450. }
  451.  
  452. /*
  453.  * Retransmitter - called periodically to perform tcp retransmissions
  454.  */
  455. static longword retran_strat = 0L; /* timeout retran strategy */
  456. static tcp_Retransmitter()
  457. {
  458.     tcp_Socket *s;
  459.  
  460.     /* only do this once per RETRAN_STRAT_TIME milliseconds */
  461.     if ( !chk_timeout( retran_strat ))
  462.     return;
  463.     retran_strat = set_ttimeout( RETRAN_STRAT_TIME );
  464.  
  465.     for ( s = tcp_allsocs; s; s = s->next ) {
  466.         if ( s->datalen > 0 || s->unhappy || s->karn_count == 1 ) {
  467.         /* retransmission strategy */
  468.         if ( chk_timeout( s->rtt_time)) {
  469.  
  470. #ifdef DEBUG
  471.     if(debug_on >1) printf("regular retran TO set unacked back to 0 from %u\n", s->unacked);
  472. #endif DEBUG
  473.                 /* strategy handles closed windows   J.D. + E.E. */
  474.                if (s->window == 0 && s->karn_count == 2)
  475.                   s->window = 1;
  476.  
  477.                 if ( s->karn_count == 0 ) {
  478.                     /* if really did timeout */
  479.  
  480.  
  481.                     s->karn_count = 2;
  482.  
  483.                     s->unacked = 0;
  484.                     /* use the backed off rto - implied, no code necessary */
  485.                     /* reduce the transmit window */
  486.                     s->cwindow =  ((s->cwindow + 1) * 3) >> 2;
  487.                     s->wwindow = 0;
  488.                 }
  489.                 if (s->datalen)
  490.                     s->flags |= tcp_FlagPUSH | tcp_FlagACK;
  491.                 tcp_send(s, __LINE__);
  492.         }
  493.     }
  494.         /* handle inactive tcp timeouts */
  495.         if ( sock_inactive && s->inactive_to ) {
  496.             if ( chk_timeout( s->inactive_to)) {
  497.                 /* this baby has timed out */
  498.                 s->err_msg = "Connection timed out - no activity";
  499.                 sock_close( s );
  500.             }
  501.         }
  502.         if ( s->timeout && chk_timeout( s->timeout)) {
  503.         if ( s->state == tcp_StateTIMEWT ) {
  504.         s->state = tcp_StateCLOSED;
  505.         tcp_unthread(s);
  506.                 break;
  507.             } else if (s->state != tcp_StateESTAB && s->state != tcp_StateESTCL ) {
  508.         s->err_msg = "Timeout, aborting";
  509.         tcp_abort(s);
  510.                 break;
  511.         }
  512.     }
  513.     }
  514.     /* do our various daemons */
  515.     if ( wattcpd ) (*wattcpd)();
  516. }
  517.  
  518.  
  519. /*
  520.  * Unthread a socket from the tcp socket list, if it's there
  521.  */
  522. static tcp_unthread(tcp_Socket *ds)
  523. {
  524.     tcp_Socket *s, **sp;
  525.  
  526.     if (!ds->rdatalen || (ds->state > tcp_StateESTCL))
  527.         ds->ip_type = 0;                /* fail io */
  528.     ds->state = tcp_StateCLOSED;   /* tcp_tick needs this */
  529.     sp = &tcp_allsocs;
  530.     for (;;) {
  531.     s = *sp;
  532.     if ( s == ds ) {
  533.         *sp = s->next;
  534.             continue;           /* unthread multiple copies if necessary */
  535.     }
  536.     if ( !s ) break;
  537.     sp = &s->next;
  538.     }
  539. }
  540.  
  541. /*
  542.  * tcp_tick - called periodically by user application
  543.  *        - returns 1 when our socket closes
  544.  *        - called with socket parameter or NULL
  545.  */
  546. tcp_tick( sock_type *s )
  547. {
  548.     in_Header *ip;
  549.     static longword timeout = 0;
  550.     static longword start = 0;
  551.  
  552.     int x;
  553.     int packettype;
  554.  
  555.     /* finish off dead sockets */
  556.     if ( s ) {
  557.         if (( s->tcp.ip_type == TCP_PROTO ) &&
  558.             ( s->tcp.state == tcp_StateCLOSED ) &&
  559.             ( s->tcp.rdatalen == 0 )) {
  560.                 tcp_unthread(s);
  561.         s->tcp.ip_type = 0;
  562.         }
  563.     }
  564.  
  565.  
  566.     /* plan our next retransmit */
  567.  
  568.     if ( !timeout )
  569.     timeout = make_timeout( tcp_RETRANSMITTIME );
  570.  
  571.     while ( ip = _eth_arrived( &packettype ) ) {
  572.     start = *realclock;
  573.  
  574.     switch ( packettype ) {
  575.     case /*0x800*/ 0x008 :
  576.         /* do IP */
  577.         if ( checksum(ip, in_GetHdrlenBytes(ip)) == 0xffff ) {
  578.                 switch ( ip->proto ) {
  579.             case TCP_PROTO :
  580.             tcp_handler(ip);
  581.             break;
  582.             case UDP_PROTO :
  583.             udp_handler(ip);
  584.             break;
  585.             case ICMP_PROTO :
  586.             icmp_handler(ip);
  587.             break;
  588.         }
  589.         } else  {
  590.         if (debug_on)
  591.             outs("IP Received BAD Checksum \n\r");
  592.         }
  593.         break;
  594.     case /*0x806*/ 0x608 :
  595.             /* do arp */
  596.         _arp_handler(ip);
  597.         break;
  598.     }
  599.     if (ip) _eth_free(ip);
  600.  
  601.     continue;
  602.     }
  603.     /* check for our outstanding packets */
  604.     tcp_Retransmitter();
  605.  
  606.     return( s->udp.ip_type );
  607. }
  608.  
  609. tcp_set_debug_state( x )
  610. int x;
  611. {
  612.     debug_on = x;
  613. }
  614.  
  615. /* returns 1 if connection is established */
  616. int tcp_established(tcp_Socket *s)
  617. {
  618.     return( s->state >= tcp_StateESTAB );
  619. }
  620.  
  621.  
  622. static udp_Write(s, datap, len)
  623. udp_Socket *s;
  624. byte *datap;
  625. int len;
  626. {
  627.     tcp_PseudoHeader ph;
  628.     struct _pkt {
  629.     in_Header  in;
  630.     udp_Header udp;
  631.     int       data;
  632. /*    longword maxsegopt; */
  633.     } *pkt;
  634.     byte *dp;
  635.     in_Header *inp;
  636.     udp_Header *udpp;
  637.  
  638.     pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr[0], /*0x800*/ 8);
  639.     dp = &pkt->data;
  640.     inp = &pkt->in;
  641.     udpp = &pkt->udp;
  642.  
  643.     inp->length = intel16( sizeof(in_Header) + UDP_LENGTH + len );
  644.  
  645.     /* udp header */
  646.     udpp->srcPort = intel16( s->myport );
  647.     udpp->dstPort = intel16( s->hisport );
  648.     udpp->checksum = 0;
  649.     udpp->length = intel16( UDP_LENGTH + len );
  650.     movmem(datap, dp, len );
  651.  
  652.     /* internet header */
  653.     inp->ver = 4;
  654.     inp->hdrlen = 5;
  655.     inp->tos = 0;
  656. /* inp->vht = 0x4500;*/   /* version 4, hdrlen 5, tos 0 */
  657.     inp->identification = intel16( ++ip_id );   /* was post inc */
  658.     inp->frag = 0;
  659.     inp->ttl = 254;
  660.     inp->proto = UDP_PROTO;    /* udp */
  661. /* inp->ttlProtocol = (250<<8) + 6; */
  662.     inp->checksum = 0;
  663.     inp->source = intel( s->myaddr );
  664.     inp->destination = intel( s->hisaddr );
  665.     inp->checksum = ~checksum( inp, sizeof(in_Header));
  666.  
  667.  
  668.     /* compute udp checksum if desired */
  669.     if ( s->sock_mode & UDP_MODE_NOCHK )
  670.     udpp->checksum = 0;
  671.     else {
  672.     ph.src = inp->source;    /* already INTELled */
  673.     ph.dst = inp->destination;
  674.     ph.mbz = 0;
  675.     ph.protocol = UDP_PROTO;    /* udp */
  676.     ph.length = udpp->length;    /* already INTELled */
  677.  
  678.     ph.checksum = checksum(&pkt->udp, intel16(ph.length));
  679.     udpp->checksum =  ~checksum(&ph, sizeof(ph));
  680.     }
  681.  
  682.     if (_dbugxmit) (*_dbugxmit)(s,inp,udpp,0);
  683.     _eth_send( intel16( inp->length ));
  684.  
  685.     return ( len );
  686. }
  687.  
  688. /*
  689.  * udp_read - read data from buffer, does large buffering
  690.  */
  691. static int udp_read(s, datap, maxlen)
  692. udp_Socket *s;
  693. byte *datap;
  694. int maxlen;
  695. {
  696.     int x;
  697.  
  698.     if (maxlen < 0) maxlen = MAXINT;
  699.     if (( x = s->rdatalen ) > 0) {
  700.     if ( x > maxlen ) x = maxlen;
  701.     if ( x > 0 ) {
  702.             if (datap) movmem( s->rdata, datap, x );
  703.         if ( s->rdatalen -= x )
  704.                 movmem( s->rdata + x, s->rdata, s->rdatalen);
  705.     }
  706.     }
  707.     return( x );
  708. }
  709.  
  710. _udp_cancel( in_Header *ip )
  711. {
  712.     int len;
  713.     udp_Header *up;
  714.     udp_Socket *s;
  715.  
  716.     /* match to a udp socket */
  717.     len = in_GetHdrlenBytes(ip);
  718.     up = (udp_Header *)((byte *)ip + len);    /* udp frame pointer */
  719.  
  720.     /* demux to active sockets */
  721.     for ( s = udp_allsocs; s; s = s->next )
  722.         if ( s->hisport != 0 &&
  723.              intel16( up->dstPort ) == s->hisport &&
  724.              intel16( up->srcPort ) == s->myport &&
  725.              intel( ip->destination ) == s->hisaddr ) break;
  726.     if ( !s ) {
  727.     /* demux to passive sockets */
  728.     for ( s = udp_allsocs; s; s = s->next )
  729.         if ( s->hisport == 0 && intel16( up->dstPort ) == s->myport ) break;
  730.     }
  731.     if (s) {
  732.         s->rdatalen = 0;
  733.     s->ip_type = 0;
  734.     }
  735. }
  736.  
  737. void *_tcp_lookup( longword hisip, word hisport, word myport )
  738. {
  739.     tcp_Socket *s;
  740.     for ( s = tcp_allsocs; s; s = s->next ) {
  741.         if ( ( myport == s->myport ) &&         /* always unique under WATTCP */
  742.              ( hisport == s->hisport ) &&
  743.              ( hisip == s->hisaddr ))
  744.                 return( s );
  745.     }
  746.     return( NULL );
  747. }
  748.  
  749.  
  750. _tcp_cancel(in_Header *ip, int code, char *msg, longword dummyip )
  751. {
  752.     int len;
  753.     tcp_Socket *s;
  754.     tcp_Header *tp;
  755.  
  756.     len = in_GetHdrlenBytes(ip);    /* check work */
  757.  
  758.     tp = (tcp_Header *)((byte *)ip + len);    /* tcp frame pointer */
  759.  
  760.     /* demux to active sockets */
  761.     for ( s = tcp_allsocs; s; s = s->next ) {
  762.         if ( intel16( tp->srcPort) == s->myport &&
  763.              intel16( tp->dstPort ) == s->hisport &&
  764.              intel( ip->destination ) == s->hisaddr ) {
  765.                 switch (code) {
  766.                     /* halt it */
  767.                     case  1 : s->err_msg = (msg) ?
  768.                                 msg : "ICMP closed connection";
  769.                               s->rdatalen = s->datalen = 0;
  770.                               s->unhappy = false;
  771.                               tcp_abort( s );
  772.                 /*      if (s->dataHandler) s->dataHandler(s, 0, -1); */
  773.                               break;
  774.                     /* slow it down */
  775.                     case  2 : s->cwindow = 1;
  776.                               s->wwindow = 1;
  777.                               s->rto <<= 2;
  778.                               s->vj_sa <<= 2;
  779.                               s->vj_sd <<= 2;
  780.                               break;
  781.                     /* icmp redirect for host */
  782.                     case  5 : /* save his NEW network address */
  783.                               _arp_resolve(dummyip, &s->hisethaddr[0]);
  784.                               break;
  785.                 }
  786.  
  787.         }
  788.     }
  789. }
  790.  
  791. static int tcp_read(tcp_Socket *s, byte *datap, int maxlen)
  792. {
  793.     int x;
  794.  
  795.     if (maxlen < 0 ) maxlen = MAXINT;
  796.     if (( x = s->rdatalen) > 0) {
  797.     if ( x > maxlen ) x = maxlen;
  798.         if ( x > 0 ) {
  799.             if (datap) movmem( s->rdata, datap, x );
  800.             if (( s->rdatalen -= x ) > 0 ) {
  801.                 movmem( s->rdata + x, s->rdata, s->rdatalen );
  802.                 tcp_sendsoon( s );   /* update the window */
  803.             } else
  804.                 tcp_send( s, __LINE__ );      /* update window el-pronto */
  805.     }
  806.     } else if ( s->state == tcp_StateCLOSWT )
  807.         tcp_close( s );
  808.     return( x );
  809. }
  810.  
  811. /*
  812.  * Write data to a connection.
  813.  * Returns number of bytes written, == 0 when connection is not in
  814.  * established state.
  815.  */
  816. static tcp_Write(tcp_Socket *s, byte *dp, int len)
  817. {
  818.     int x;
  819.  
  820.     if (len < 0 ) len = MAXINT;
  821.     /* no longer uses tcp_MaxData */
  822.     if ( s->state != tcp_StateESTAB ) len = 0;
  823.     if ( len > (x = s->maxrdatalen - s->datalen) ) len = x;
  824.     if ( len > 0 ) {
  825.         movmem( dp, s->data + s->datalen, len );
  826.  
  827.     s->datalen += len;
  828.     s->unhappy = true;    /* redundant because we have outstanding data */
  829.  
  830.         if ( s->sock_mode & TCP_LOCAL )
  831.             s->sock_mode &= ~TCP_LOCAL;
  832.         else {
  833.             if ( s->sock_mode & TCP_MODE_NONAGLE ) {
  834.                 tcp_send( s, __LINE__ );
  835.             } else {
  836.                 /* transmit if first data or reached MTU */
  837.                 /* not true MTU, but better than nothing */
  838.                 if (( s->datalen == len ) || ( s->datalen > (s->mss)/2 ))
  839.                     tcp_send( s, __LINE__ );
  840.                 else
  841.                     tcp_sendsoon( s );
  842.             }
  843.     }
  844.     }
  845.  
  846.     return ( len );
  847. }
  848.  
  849. /*
  850.  * Send pending data
  851.  */
  852. static tcp_Flush(tcp_Socket *s)
  853. {
  854.     if ( s->datalen > 0 ) {
  855.         s->flags |= tcp_FlagPUSH;
  856.         tcp_send(s, __LINE__);
  857.     }
  858. }
  859.  
  860. /*
  861.  * Handler for incoming packets.
  862.  */
  863. static udp_handler(in_Header *ip)
  864. {
  865.     udp_Header *up;
  866.     tcp_PseudoHeader ph;
  867.     word len;
  868.     byte *dp;
  869.     longword temp;
  870.     udp_Socket *s;
  871.  
  872.     temp = intel( ip->destination );
  873.     if ( ~temp & ~sin_mask == 0 ||  /* broadcast */
  874.         ((( temp - my_ip_addr) > multihomes ) && my_ip_addr))
  875.           return;
  876.  
  877.  
  878.     len = in_GetHdrlenBytes(ip);
  879.     up = (udp_Header *)((byte *)ip + len);    /* udp segment pointer */
  880.     len = intel16( up->length );
  881.  
  882.     /* demux to active sockets */
  883.     for ( s = udp_allsocs; s; s = s->next ) {
  884.         if ( s->safetysig != SAFETYUDP ) {
  885.             if (debug_on) outs("chain error in udp\r\n");
  886.         }
  887.         if ( s->hisport != 0 &&
  888.          intel16( up->dstPort ) == s->myport &&
  889.          intel16( up->srcPort ) == s->hisport &&
  890.              intel( ip->destination )   == s->myaddr     &&
  891.          intel( ip->source ) == s->hisaddr ) break;
  892.     }
  893.     if (_dbugrecv) (*_dbugrecv)(s,ip,up,0);
  894.     if ( !s ) {
  895.         /* demux to passive sockets */
  896.     for ( s = udp_allsocs; s; s = s->next )
  897.         if ( s->hisaddr == 0 && intel16( up->dstPort ) == s->myport ) {
  898.         if (_arp_resolve(intel(ip->source), &s->hisethaddr[0])) {
  899.             s->hisaddr = intel( ip->source );
  900.             s->hisport = intel16( up->srcPort );
  901.         }
  902.                 s->myaddr = intel( ip->destination );
  903.         break;
  904.         }
  905.     }
  906.     if ( !s ) {
  907.     /* demux to broadcast sockets */
  908.     for ( s = udp_allsocs; s; s = s->next )
  909.         if ( s->hisaddr == 0xffffffff && intel16( up->dstPort ) == s->myport ) break;
  910.     }
  911.  
  912.     if ( !s ) {
  913.     if (debug_on) outs("discarding...");
  914.     return;
  915.     }
  916.  
  917.     if ( up->checksum ) {
  918.     ph.src = ip->source;    /* already INTELled */
  919.     ph.dst = ip->destination;
  920.     ph.mbz = 0;
  921.     ph.protocol = UDP_PROTO;
  922.     ph.length = up->length;
  923.     ph.checksum =  checksum(up, len);
  924.     if (checksum(&ph, sizeof( tcp_PseudoHeader)) != 0xffff)
  925.         return;
  926.     }
  927.  
  928.     /* process user data */
  929.     if ( (len -= UDP_LENGTH ) > 0) {
  930.     dp = (byte *)( up );
  931.         if (s->dataHandler) s->dataHandler( s, &dp[ UDP_LENGTH ], len , &ph, up);
  932.     else {
  933.             if (len > s->maxrdatalen ) len = s->maxrdatalen;
  934.         movmem( &dp[ UDP_LENGTH ], s->rdata, len );
  935.         s->rdatalen = len;
  936.     }
  937.     }
  938. }
  939.  
  940. static tcp_handler(in_Header *ip)
  941. {
  942.     tcp_Header *tp;
  943.     tcp_PseudoHeader ph;
  944.     int len;
  945.     byte *dp;
  946.     int diff;
  947.     tcp_Socket *s;
  948.     word flags;
  949.     long diffticks, ldiff;    /* must be signed */
  950.     long scheduleto;
  951.  
  952.  
  953.     if ( (longword)(intel( ip->destination ) - my_ip_addr) > multihomes )
  954.         return;
  955.  
  956.     len = in_GetHdrlenBytes(ip);
  957.     len = intel16( ip->length ) - len;        /* len of tcp data */
  958.  
  959.     len = in_GetHdrlenBytes(ip);
  960.     tp = (tcp_Header *)((byte *)ip + len);    /* tcp frame pointer */
  961.     len = intel16( ip->length ) - len;        /* len of tcp data */
  962.     flags = intel16( tp->flags );
  963.  
  964.     if (debug_on > 1) {
  965.             mono[160]++;
  966.             colour[160]++;
  967.             mono[162] = colour[162] = (flags & tcp_FlagSYN) ? 'S' : ' ';
  968.             mono[164] = colour[164] = (flags & tcp_FlagACK) ? 'A' : ' ';
  969.             mono[166] = colour[166] = (flags & tcp_FlagFIN) ? 'F' : ' ';
  970.             mono[168] = colour[168] = (flags & tcp_FlagRST) ? 'R' : ' ';
  971.         }
  972.  
  973.  
  974.     /* demux to active sockets */
  975.     for ( s = tcp_allsocs; s; s = s->next ) {
  976.         if ( s->safetysig != SAFETYTCP ) {
  977.             if (debug_on) outs("chain error in tcp\r\n");
  978.         }
  979.     if ( s->hisport != 0 &&
  980.          intel16( tp->dstPort ) == s->myport &&
  981.          intel16( tp->srcPort ) == s->hisport &&
  982.              intel( ip->destination )   == s->myaddr     &&
  983.          intel( ip->source ) == s->hisaddr ) break;
  984.     }
  985.     if ( !s && (flags & tcp_FlagSYN)) {
  986.     /* demux to passive sockets, must be a new session */
  987.     for ( s = tcp_allsocs; s; s = s->next )
  988.             if ((s->hisport == 0) && (intel16( tp->dstPort ) == s->myport )) {
  989.                 s->myaddr = intel( ip->destination );
  990.         break;
  991.             }
  992.     }
  993.  
  994.  
  995.     if (_dbugrecv) (*_dbugrecv)(s,ip,tp,0);
  996.     if ( !s ) {
  997.         if (!(flags & tcp_FlagRST)) tcp_rst( ip, tp );
  998.     return;
  999.     }
  1000.  
  1001.     ph.src = ip->source;    /* already INTELled */
  1002.     ph.dst = ip->destination;
  1003.     ph.mbz = 0;
  1004.     ph.protocol = TCP_PROTO;
  1005.     ph.length = intel16( len );
  1006.     ph.checksum =  checksum(tp, len);
  1007.     if ( checksum(&ph, sizeof(ph)) != 0xffff ) {
  1008.      if (debug_on) outs("bad tcp checksum \n\r");
  1009.  
  1010.          /* tester */
  1011.          ph.checksum =  checksum(tp, len);
  1012.          checksum(&ph, sizeof(ph));
  1013.  
  1014.          tcp_sendsoon( s );
  1015.      return;
  1016.     }
  1017.  
  1018. /* reset code */
  1019.     if ( flags & tcp_FlagRST ) {
  1020.     if (debug_on) outs("\7\7\7\7\7\7\7connection reset\n");
  1021.         s->rdatalen = s->datalen = 0;
  1022.         s->err_msg = "Remote reset connection";
  1023.     s->state = tcp_StateCLOSED;
  1024. /*    if (s->dataHandler) s->dataHandler(s, 0, -1); */
  1025.     tcp_unthread(s);
  1026.     return;
  1027.     }
  1028.  
  1029.     if ( sock_inactive )
  1030.         s->inactive_to = set_timeout( sock_inactive );
  1031.  
  1032.  
  1033.     /* update our retransmission stuff */
  1034.     /* new algorithms */
  1035.     if (s->karn_count == 2) {
  1036.         s->karn_count = 0;
  1037. #ifdef DEBUG
  1038.         if (debug_on > 1 ) printf("finally got it safely zapped from %u to ????\n\r",s->unacked);
  1039. #endif /* DEBUG */
  1040.     } else {
  1041.         if ( s->vj_last ) {
  1042.             /* unnecessary to use unhappy || s->datalen ) */
  1043.             if ((diffticks = set_ttimeout( 0 ) - s->vj_last) >= 0 ) {
  1044.                 /* we ignore the overnight case */
  1045.                 diffticks -= (longword)( s->vj_sa >> 3 );
  1046.                 s->vj_sa += (int)diffticks;
  1047.                 if (diffticks < 0)
  1048.                     diffticks = - diffticks;
  1049.                 diffticks -= (s->vj_sd >> 2);
  1050.                 s->vj_sd += (int)diffticks;
  1051.                 if (s->vj_sa > MAXVJSA) s->vj_sa = MAXVJSA;
  1052.                 if (s->vj_sd > MAXVJSD) s->vj_sd = MAXVJSD;
  1053.             }
  1054.             /* only recompute rtt hence rto after success */
  1055.             s->rto = 1 + ((s->vj_sa >> 2) + (s->vj_sd)) >> 1 ;
  1056. #ifdef DEBUG
  1057.             if (debug_on > 1 ) printf("rto  %u  sa  %u  sd  %u   cwindow %u  wwindow %u  unacked %u\n",
  1058.                 s->rto, s->vj_sa, s->vj_sd, s->cwindow, s->wwindow, s->unacked );
  1059. #endif /* DEBUG */
  1060.     }
  1061.         s->karn_count = 0;
  1062.         if ( s->wwindow++ >= s->cwindow ) {
  1063.             s->cwindow++;
  1064.             s->wwindow = 0;
  1065.         }
  1066.     }
  1067.     /* all new */
  1068.     scheduleto = set_ttimeout( s->rto + 2 );
  1069.     if ( s->rtt_time < scheduleto ) s->rtt_time = scheduleto;
  1070.  
  1071.  
  1072.     switch ( s->state ) {
  1073.  
  1074.     case tcp_StateLISTEN:    /* accepting SYNs */
  1075.             /* save his ethernet address */
  1076.             movmem(&((((eth_Header *)ip) - 1)->source[0]), &s->hisethaddr[0], sizeof(eth_address));
  1077.             if ( flags & tcp_FlagSYN ) {
  1078.  
  1079.                 if ( ip->tos > s->tos )
  1080.                     s->tos = ip->tos;
  1081.                 else if ( ip->tos < s->tos ) {
  1082.                     /* RFC 793 says we should close connection */
  1083.                     /* we best not do that while SunOS ignores TOS */
  1084.                 }
  1085.  
  1086.                 s->acknum = intel( tp->seqnum ) + 1;
  1087.         s->hisport = intel16( tp->srcPort );
  1088.         s->hisaddr = intel( ip->source );
  1089.         s->flags = tcp_FlagSYN | tcp_FlagACK;
  1090.                 s->state = tcp_StateSYNREC;
  1091.         s->unhappy = true;
  1092.                 tcp_send(s, __LINE__);    /* we must respond immediately */
  1093.  
  1094.         s->timeout = set_timeout( tcp_TIMEOUT );
  1095.         } else
  1096.         tcp_rst( ip , tp );  /* send a reset */
  1097.  
  1098.         return( 1 );
  1099.         break;      /* unreachable */
  1100.  
  1101.     case tcp_StateSYNSENT:  /* added ACK Section */
  1102.         if ( flags & tcp_FlagSYN ) {
  1103.  
  1104.                 if ( ip->tos > s->tos )
  1105.                     s->tos = ip->tos;
  1106.                 else if ( ip->tos < s->tos ) {
  1107.                     /* RFC 793 says we should close connection */
  1108.                     /* we best not do that while SunOS ignores TOS */
  1109.                 }
  1110.  
  1111.                 s->flags = tcp_FlagACK;
  1112.         s->timeout = set_timeout( tcp_TIMEOUT );
  1113.  
  1114.         /* FlagACK means connection established, else SYNREC */
  1115.         if ( flags & tcp_FlagACK) {
  1116.             /* but is it for the correct session ? */
  1117.                 if (tp->acknum == intel(s->seqnum + 1)) {
  1118.                 s->state = tcp_StateESTAB;
  1119.                 s->seqnum++;    /* good increment */
  1120.                 s->acknum = intel( tp->seqnum  ) + 1;   /* 32 bits */
  1121.                 tcp_ProcessData(s, tp, len);    /* someone may try it */
  1122.                 s->unhappy = true;             /* rely on their attempts */
  1123.                 tcp_send( s, __LINE__ );
  1124.             } else {
  1125.                 /* wrong ack, force a RST and resend SYN soon*/
  1126.                 s->flags = tcp_FlagRST;
  1127.                 s->unhappy = true;
  1128.                 tcp_send( s, __LINE__ );
  1129.                 s->flags = tcp_FlagSYN;
  1130.                 tcp_send( s, __LINE__ );
  1131.             }
  1132.         } else {
  1133.             s->acknum++;
  1134.             s->state = tcp_StateSYNREC;
  1135.             return( 1 );
  1136.         }
  1137.             } else
  1138.                 tcp_rst( ip, tp );
  1139.         break;
  1140.  
  1141.     case tcp_StateSYNREC:    /* recSYNSENT, sentACK, waiting  EST */
  1142.         if ( flags & tcp_FlagSYN ) {
  1143.         s->flags = tcp_FlagSYN | tcp_FlagACK;
  1144.         s->unhappy = true;
  1145.                 tcp_send(s, __LINE__);
  1146.         s->timeout = set_timeout( tcp_TIMEOUT );
  1147.         return( 1 );
  1148.         }
  1149.         if ( (flags & tcp_FlagACK) && (intel( tp->acknum ) == (s->seqnum + 1))) {
  1150.                 if ( (s->window = intel16( tp->window )) > 0x7fff )
  1151.                     s->window = 0x7fff;
  1152.         s->flags = tcp_FlagACK;
  1153.                 s->state = tcp_StateESTAB;
  1154.                 s->seqnum++;
  1155.                 s->timeout = 0;     /* never timeout */
  1156.                 s->unhappy = false;
  1157.         return( 1 );
  1158.         }
  1159.  
  1160.         break;
  1161.     case tcp_StateESTAB:
  1162.         case tcp_StateESTCL:
  1163.         case tcp_StateCLOSWT:
  1164.  
  1165.             /* handle lost SYN */
  1166.             if ((flags & tcp_FlagSYN) && (flags & tcp_FlagACK)) {
  1167.                 tcp_send( s, __LINE__ );
  1168.                 return;
  1169.             }
  1170.  
  1171.         if ( !(flags & tcp_FlagACK)) return;  /* must ack somthing */
  1172.             if ( flags & tcp_FlagSYN ) {
  1173.                 tcp_rst( ip , tp );
  1174.                 return;
  1175.             }
  1176.         s->timeout = 0l;    /* we do not timeout at this point */
  1177.  
  1178.         /* process ack value in packet - but only if it falls
  1179.          * within current window */
  1180.  
  1181.         ldiff = intel( tp->acknum ) - s->seqnum;
  1182.         diff = (int) ldiff;
  1183.  
  1184.             if ( ldiff >= 0 && diff <= s->datalen ) {
  1185.         s->datalen -= diff;
  1186.                 s->unacked -= diff;
  1187.                 if (s->datalen < 0) s->datalen = 0; /* remote proto error */
  1188.                 if ( s->queuelen ) {
  1189.                     s->queue += diff;
  1190.                     s->queuelen -= diff;
  1191.                 } else
  1192.                     movmem(s->data + diff, s->data, s->datalen );
  1193.         s->seqnum += ldiff;
  1194.             } else {
  1195. #ifdef DEBUG
  1196.     if(debug_on >1) printf("tcphandler confused so set unacked back to 0 from %u\n",s->unacked);
  1197. #endif DEBUG
  1198.                 s->unacked = 0;
  1199.             }
  1200.             if (s->unacked < 0) s->unacked = 0;
  1201.  
  1202.         s->flags = tcp_FlagACK;
  1203.         tcp_ProcessData(s, tp, len);
  1204.  
  1205.             if (( flags & tcp_FlagFIN ) && (s->state != tcp_StateCLOSWT )
  1206.                 && ( s->acknum == intel( tp->seqnum ))) {
  1207.                 s->acknum ++;
  1208.                 if ( ! s->err_msg ) s->err_msg = "Connection closed";
  1209.                 s->state = tcp_StateCLOSWT;
  1210.                 tcp_send( s, __LINE__ );
  1211.                 s->state = tcp_StateLASTACK;
  1212.                 s->flags |= tcp_FlagFIN;
  1213.                 s->unhappy = true;
  1214.             }
  1215.  
  1216.             if ( diff > 0 || len > 0 ) {
  1217.                 /* need to update window, but how urgent ??? */
  1218.                 if ( diff > 0 || (len > (s->mss >> 1))) {
  1219.                     tcp_send( s, __LINE__ );
  1220.                 } else
  1221.                     tcp_sendsoon( s );
  1222.  
  1223.             }
  1224.             if ( s->state == tcp_StateESTCL )
  1225.                 tcp_close( s );
  1226.         return( 1 );
  1227.         break;    /* dummy for compiler */
  1228.  
  1229.     case tcp_StateFINWT1:
  1230.         /* They have not necessarily read all the data yet, we must
  1231.            still supply it as requested */
  1232.  
  1233.         ldiff = intel( tp->acknum ) - s->seqnum;
  1234.         diff = (int) ldiff;
  1235.         if ( ldiff >= 0 && diff <= s->datalen ) {
  1236.         s->datalen -= diff;
  1237.                 s->unacked -= diff;
  1238.                 if (s->datalen < 0) s->datalen = 0;
  1239.                 if ( s->queuelen ) {
  1240.                     s->queue += diff;
  1241.                     s->queuelen -= diff;
  1242.                 } else
  1243.                     movmem(s->data + diff, s->data, s->datalen );
  1244.         s->seqnum += ldiff;
  1245.                 if (ldiff == 0 || s->unacked < 0) s->unacked = 0;
  1246.  
  1247.         }
  1248.  
  1249.         /* they may still be transmitting data, we must read it */
  1250.  
  1251.         tcp_ProcessData(s, tp, len);
  1252.  
  1253.         /* check if other tcp has acked all sent data and is ready
  1254.            to change states */
  1255.  
  1256.             if ( flags & (tcp_FlagFIN|tcp_FlagACK) == tcp_FlagFIN|tcp_FlagACK) {
  1257.         /* trying to do similtaneous close */
  1258.         if (( intel( tp->acknum ) >= s->seqnum + 1 ) &&
  1259.             ( intel( tp->seqnum) == s->acknum )) {
  1260.             s->seqnum++;
  1261.             s->acknum++;
  1262.             s->flags = tcp_FlagACK;
  1263.                     tcp_send( s, __LINE__ );
  1264.                     s->unhappy = false;
  1265.                     s->timeout = set_timeout( 2 );
  1266.                     s->state = tcp_StateCLOSED;
  1267.         }
  1268.         } else if ( flags & tcp_FlagACK ) {
  1269.         /* other side is legitimately acking our fin */
  1270.         if (( intel( tp->acknum ) == s->seqnum + 1 ) &&
  1271.             ( intel( tp->seqnum ) == s->acknum ) &&
  1272.             (  s->datalen == 0 )) {
  1273.                         s->seqnum++;
  1274.                         s->acknum++;
  1275.                         s->state = tcp_StateFINWT2;
  1276.                         s->timeout = set_timeout( 3 );
  1277.                         s->unhappy = false; /* we don't send anything */
  1278.         }
  1279.         }
  1280.         break;
  1281.  
  1282.     case tcp_StateFINWT2:
  1283.         if ((flags & (tcp_FlagACK | tcp_FlagFIN)) ==
  1284.           tcp_FlagACK | tcp_FlagFIN) {
  1285.         if (( intel( tp->acknum ) == s->seqnum ) &&
  1286.             ( intel( tp->seqnum ) == s->acknum )) {
  1287.             s->acknum++;
  1288.             s->flags = tcp_FlagACK;
  1289.                     tcp_send( s, __LINE__ );
  1290.             s->unhappy = false;    /* we don't send anything */
  1291.             s->timeout = set_timeout( 2 );
  1292.                     s->state = tcp_StateCLOSED;
  1293.             return( 1 );
  1294.         }
  1295.         }
  1296.         break;
  1297.  
  1298.     case tcp_StateCLOSING:
  1299.         if ((flags & (tcp_FlagACK | tcp_FlagFIN)) == tcp_FlagACK ) {
  1300.         if (( tp->acknum == intel(s->seqnum) ) &&
  1301.             ( tp->seqnum == intel(s->acknum))) {
  1302.             s->state = tcp_StateTIMEWT;
  1303.             s->timeout = set_timeout( tcp_TIMEOUT );
  1304.             s->unhappy = false;
  1305.         }
  1306.         }
  1307.         break;
  1308.  
  1309.     case tcp_StateLASTACK:
  1310.         if ( flags & tcp_FlagFIN ) {
  1311.         /* they lost our two packets, back up */
  1312.         s->flags = tcp_FlagACK | tcp_FlagFIN;
  1313.                 tcp_send( s, __LINE__ );
  1314.                 s->unhappy = TRUE;  /* FALSE; */
  1315.         return( 1 );
  1316.         } else {
  1317.         if (( intel( tp->acknum ) == (s->seqnum + 1 )) &&
  1318.             ( intel( tp->seqnum ) == s->acknum )) {
  1319.             s->state = tcp_StateCLOSED;     /* no 2msl necessary */
  1320.             s->unhappy = false;             /* we're done */
  1321.             return( 1 );
  1322.             }
  1323.         }
  1324.         break;
  1325.  
  1326.     case tcp_StateTIMEWT:
  1327.             if ( flags & (tcp_FlagACK | tcp_FlagFIN) == tcp_FlagACK | tcp_FlagFIN) {
  1328.                 /* he needs an ack */
  1329.                 s->flags = tcp_FlagACK;
  1330.                 tcp_send( s, __LINE__ );
  1331.                 s->unhappy = false;
  1332.                 s->state = tcp_StateCLOSED;     /* support 2 msl in rst code */
  1333.             }
  1334.             break;
  1335.     }
  1336.     if (s->unhappy) tcp_sendsoon(s);
  1337. }
  1338.  
  1339. /*
  1340.  * Process the data in an incoming packet.
  1341.  * Called from all states where incoming data can be received: established,
  1342.  * fin-wait-1, fin-wait-2
  1343.  */
  1344. static tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, int len)
  1345. {
  1346.     long ldiff;
  1347.     int diff, x;
  1348.     word flags;
  1349.     byte *dp;
  1350.  
  1351.     word *options, numoptions, opt_temp;
  1352.  
  1353.     if ( (s->window = intel16( tp->window )) > 0x7fff )
  1354.         s->window = 0x7fff;
  1355.  
  1356.     flags = intel16( tp->flags );
  1357.     ldiff = s->acknum - intel( tp->seqnum );
  1358.  
  1359.     if ( flags & tcp_FlagSYN ) ldiff--;  /* back up to 0 */
  1360.     diff = (int) ldiff;
  1361.  
  1362.     /* find the data portion */
  1363.     x = tcp_GetDataOffset(tp) << 2;    /* quadword to byte format */
  1364.     dp = (byte *)tp + x;
  1365.  
  1366.     /* process those options */
  1367.     if ( numoptions = x - sizeof( tcp_Header )) {
  1368.         options = (byte *)(tp) + sizeof( tcp_Header);
  1369.     while ( numoptions-- > 0 ) {
  1370.         switch ( *options++ ) {
  1371.         case  0 : numoptions = 0;    /* end of options */
  1372.               break;
  1373.         case  1 : break;        /* nop */
  1374.  
  1375.               /* we are very liberal on MSS stuff */
  1376.         case  2 : if (*options == 2) {
  1377.                   opt_temp = intel16( *(word*)(&options[1]));
  1378.                   if (opt_temp < s->mss )
  1379.                   s->mss = opt_temp;
  1380.               }
  1381.               numoptions -= 2 + *options;
  1382.               options += *options;
  1383.               break;
  1384.         }
  1385.     }
  1386.     }
  1387.     /* done option processing */
  1388.  
  1389.     len -= x;        /* remove the header length */
  1390.     if ( ldiff >= 0 ) {  /* skip already received bytes */
  1391.     dp += diff;
  1392.     len -= diff;
  1393.  
  1394.     if (s->dataHandler) {
  1395.         s->acknum += s->dataHandler(s, dp, len);
  1396.     } else {
  1397.         /* no handler, just dump to buffer, should be indexed, handles goofs */
  1398.         /* limit receive size to our window */
  1399.         if ( s->rdatalen >= 0 ) {
  1400.                 if ( len > ( x = s->maxrdatalen - s->rdatalen )) {
  1401.             len = x;
  1402.                 }
  1403.         if ( len > 0 ) {
  1404.             s->acknum += len;    /* our new ack begins at end of data */
  1405.                     movmem(dp, s->rdata + s->rdatalen, len );
  1406.             s->rdatalen += len;
  1407. /*
  1408.                     s->karn_count = 3;
  1409. */
  1410.         }
  1411.         }
  1412.         }
  1413.         s->unhappy = (s->datalen) ? true : false;
  1414.         if (ldiff == 0 && s->unacked && chk_timeout( s->rtt_lasttran )) {
  1415. #ifdef DEBUG
  1416.             if(debug_on >1) printf("data process timeout so set unacked back to 0 from %u\n",s->unacked);
  1417. #endif DEBUG
  1418.             s->unacked = 0;
  1419.         }
  1420.     } else {
  1421.         tcp_sendsoon( s );
  1422.     }
  1423.  
  1424.     s->timeout = set_timeout( tcp_TIMEOUT );
  1425.     return;
  1426. }
  1427.  
  1428. /*
  1429.  * Format and send an outgoing segment
  1430.  */
  1431. static tcp_send(tcp_Socket *s, int line)
  1432. {
  1433.     tcp_PseudoHeader ph;
  1434.     struct _pkt {
  1435.     in_Header in;
  1436.     tcp_Header tcp;
  1437.     word maxsegopt[2];
  1438.     } *pkt;
  1439.     byte *dp;
  1440.     in_Header *inp;
  1441.     tcp_Header *tcpp;
  1442.     int senddatalen, sendtotlen, sendpktlen, startdata, sendtotdata;
  1443.  
  1444.     int ippkt;         /* 1..s->cwindow */
  1445.  
  1446.     s->recent = 0;
  1447.     pkt = (struct _pkt *)_eth_formatpacket(&s->hisethaddr[0], /*0x800*/ 8);
  1448.     dp = &pkt->maxsegopt;  /* dp constant for multi-packet sends */
  1449.     inp = &pkt->in;
  1450.     tcpp = &pkt->tcp;
  1451.  
  1452.  
  1453.     /* this is our total possible send size */
  1454.     if ( s->karn_count != 2 ) {
  1455.         /* BUG FIX : jason dent found this */
  1456. /*      sendtotdata = min( s->datalen - s->unacked, s->window );  */
  1457.         sendtotdata = max (min ( s->datalen, s->window ) - s->unacked, 0);
  1458.         startdata = s->unacked;
  1459.     } else {
  1460.         sendtotdata = (s->datalen >= s->window)? s->window : s->datalen;
  1461.         startdata = 0;
  1462.     }
  1463. /*
  1464.     if (sendtotdata < 0) sendtotdata = 0;
  1465. */
  1466.     sendtotlen = 0;    /* running count of what we've sent */
  1467.  
  1468.     /* step through our packets */
  1469.     for ( ippkt = 1; ippkt <= s->cwindow; ++ippkt ) {
  1470.         /* adjust size for each packet */
  1471.         senddatalen = min( sendtotdata, s->mss );
  1472.  
  1473.     /*
  1474.         sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
  1475.         inp->length = intel16( sendpktlen );
  1476.     */
  1477.         /* tcp header */
  1478.         tcpp->srcPort = intel16( s->myport );
  1479.         tcpp->dstPort = intel16( s->hisport );
  1480.         tcpp->seqnum = intel( s->seqnum + startdata ); /* unacked - no longer sendtotlen */
  1481.         tcpp->acknum = intel( s->acknum );
  1482.  
  1483.         tcpp->window = intel16( s->maxrdatalen - s->rdatalen );
  1484.         tcpp->flags = intel16( s->flags | 0x5000 );
  1485.         tcpp->checksum = 0;
  1486.         tcpp->urgentPointer = 0;
  1487.  
  1488.         /* do options if this is our first packet */
  1489.         if ( s->flags & tcp_FlagSYN ) {
  1490.             sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header ) + 4;
  1491.             tcpp->flags = intel16( intel16( tcpp->flags) + 0x1000 );
  1492.             pkt->maxsegopt[0] = 0x0402;
  1493.             pkt->maxsegopt[1] = intel16( s->mss );
  1494.             dp += 4;
  1495.         } else {
  1496.             /* handle packets with data */
  1497.             if (senddatalen > 0) {
  1498.                 sendpktlen = senddatalen + sizeof( tcp_Header ) + sizeof( in_Header );
  1499.  
  1500.                 /* get data from appropriate place */
  1501.                 if (s->queuelen) movmem(s->queue + startdata, dp, senddatalen );
  1502.                 else movmem(s->data + startdata, dp, senddatalen);
  1503. /*                dp[ senddatalen ] = 0; */
  1504.             } else {
  1505.             /* handle no-data, not-first-SYN packets */
  1506.                 sendpktlen = sizeof( tcp_Header ) + sizeof( in_Header );
  1507.             }
  1508.         }
  1509.  
  1510.         /* internet header */
  1511.         inp->ver = 4;
  1512.         inp->hdrlen = 5;
  1513.         inp->tos = s->tos;
  1514.         inp->identification = intel16( ++ip_id );   /* was post inc */
  1515.         inp->frag = 0;
  1516.         inp->ttl = 254;
  1517.         inp->proto = TCP_PROTO;
  1518.         inp->checksum = 0;
  1519.         inp->source = intel( s->myaddr );
  1520.         inp->destination = intel( s->hisaddr );
  1521.         inp->length = intel16( sendpktlen );
  1522.  
  1523.         inp->checksum = ~checksum( inp, sizeof(in_Header));
  1524.  
  1525.         /* compute tcp checksum */
  1526.         ph.src = inp->source;   /* already INTELled */
  1527.         ph.dst = inp->destination;
  1528.         ph.mbz = 0;
  1529.         ph.protocol = 6;
  1530.         ph.length = intel16( sendpktlen - sizeof(in_Header));
  1531. /*
  1532.         ph.checksum = checksum(&pkt->tcp, (sendpktlen - sizeof(in_Header) +1) & 0xfffe);
  1533. */
  1534.         ph.checksum = checksum(&pkt->tcp, sendpktlen - sizeof(in_Header));
  1535.  
  1536.         tcpp->checksum = ~checksum(&ph, sizeof(ph));
  1537.  
  1538.         if (_dbugxmit) (*_dbugxmit)(s,inp,tcpp, line);
  1539.         if (debug_on > 1) {
  1540.             mono[0]++;
  1541.             colour[0]++;
  1542.             mono[2] = colour[2] = (s->flags & tcp_FlagSYN) ? 'S' : ' ';
  1543.             mono[4] = colour[4] = (s->flags & tcp_FlagACK) ? 'A' : ' ';
  1544.             mono[6] = colour[6] = (s->flags & tcp_FlagFIN) ? 'F' : ' ';
  1545.             mono[8] = colour[8] = (s->flags & tcp_FlagRST) ? 'R' : ' ';
  1546.         }
  1547.         if ( _eth_send( intel16( inp->length ))) { /* encounterred error */
  1548.             tcp_sendsoon( s );
  1549.             return;
  1550.         }
  1551.  
  1552.         /* do next ip pkt */
  1553.         sendtotlen += senddatalen;
  1554.         startdata += senddatalen;
  1555.         sendtotdata -= senddatalen;
  1556.         if (sendtotdata <= 0 ) break;
  1557.     }
  1558.     s->unacked = startdata;
  1559. #ifdef DEBUG
  1560. if (debug_on) printf(" Sent %u/%u bytes in %u/%u packets  with (%u) unacked  SYN %lu  line %u\n",
  1561.         sendtotlen, s->window, ippkt, s->cwindow, s->unacked, s->seqnum, line);
  1562. #endif DEBUG
  1563.     s->vj_last = 0;
  1564.     if ( s->karn_count == 2 ) {
  1565.         if (s->rto) s->rto = (s->rto * 3) / 2;
  1566.         else s->rto = 4;
  1567.     } else {
  1568.         /* vj_last nonzero if we expect an immediate response */
  1569.         if (s->unhappy || s->datalen)
  1570.             s->vj_last = set_ttimeout( 0 );
  1571.     s->karn_count = 0;
  1572.     }
  1573.     s->rtt_time = set_ttimeout( s->rto + 2 );
  1574.     if (sendtotlen > 0 ) s->rtt_lasttran =  s->rtt_time + s->rto;
  1575. }
  1576. /*
  1577.  * Format and send a reset tcp packet
  1578.  */
  1579. tcp_rst( in_Header *his_ip, tcp_Header *oldtcpp)
  1580. {
  1581.     tcp_PseudoHeader ph;
  1582.     struct _pkt {
  1583.         in_Header in;
  1584.         tcp_Header tcp;
  1585.     word maxsegopt[2];
  1586.     } *pkt, *his_pkt;
  1587.  
  1588.     static longword nextrst = 0L;
  1589.     byte *dp;
  1590.     word oldflags;
  1591.     in_Header *inp;
  1592.     tcp_Header *tcpp;
  1593.     eth_Header *eth;
  1594.     int sendtotlen;    /* length of packet */
  1595.     int temp;
  1596.     longword templong;
  1597.  
  1598.     /* see RFC 793 page 65 for details */
  1599.  
  1600.     if ( !chk_timeout( nextrst )) return;
  1601.     nextrst = set_ttimeout( 1 );
  1602.  
  1603.     oldflags = intel16( oldtcpp->flags );
  1604.     if (oldflags & tcp_FlagRST ) return( 0 );
  1605. #ifdef NEVER
  1606.     if ( (oldflags & (tcp_FlagACK | tcp_FlagFIN)) == (tcp_FlagACK | tcp_FlagFIN) ){
  1607.         templong = oldtcpp->seqnum;
  1608.         oldtcpp->seqnum = oldtcpp->acknum;
  1609.         oldtcpp->acknum = templong;
  1610.         oldflags = tcp_FlagACK;
  1611.     } else if ((oldflags & (tcp_FlagSYN | tcp_FlagACK)) ==  tcp_FlagSYN ) {
  1612.         oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + 1 );
  1613.         oldtcpp->seqnum = 0;
  1614.         oldflags = tcp_FlagACK | tcp_FlagRST;
  1615.     } else if ( oldflags & tcp_FlagACK ) {
  1616.         oldtcpp->seqnum = oldtcpp->acknum;
  1617.         oldtcpp->acknum = 0;
  1618.     } else {
  1619.         oldtcpp->acknum = intel( intel(oldtcpp->seqnum) + 1);
  1620.         oldtcpp->seqnum = 0;
  1621.     }
  1622.     if ( oldflags & ( tcp_FlagFIN | tcp_FlagSYN ) == 0 )
  1623.         oldflags ^= tcp_FlagACK | tcp_FlagRST;
  1624.  
  1625.     if ( oldflags & tcp_FlagACK ) {
  1626.         oldtcpp->seqnum = oldtcpp->acknum;
  1627.  
  1628. #else
  1629.     /* better strategy - Dean Roth */
  1630.     if ( oldflags & tcp_FlagACK ) {
  1631.         oldtcpp->seqnum = oldtcpp->acknum;
  1632.         oldtcpp->acknum = 0;
  1633.     } else {
  1634.         temp = intel16( his_ip->length) - in_GetHdrlenBytes( his_ip );
  1635.         oldtcpp->acknum = intel( intel( oldtcpp->seqnum ) + temp );
  1636.         oldtcpp->seqnum = 0;
  1637.     }
  1638.     oldflags = tcp_FlagRST;
  1639. #endif
  1640.  
  1641.     his_pkt  = (struct _pkt*)( his_ip );
  1642.  
  1643.     /* convoluted mechanism - reads his ethernet address or garbage */
  1644.     eth = _eth_hardware( his_ip );
  1645.  
  1646.     pkt = (struct _pkt *)_eth_formatpacket( eth, 8);
  1647.     dp = &pkt->maxsegopt;
  1648.     inp = &pkt->in;
  1649.     tcpp = &pkt->tcp;
  1650.  
  1651.     sendtotlen = sizeof( tcp_Header ) + sizeof( in_Header );
  1652.     inp->length = intel16( sendtotlen );
  1653.  
  1654.     /* tcp header */
  1655.     tcpp->srcPort = oldtcpp->dstPort;
  1656.     tcpp->dstPort = oldtcpp->srcPort;
  1657.     tcpp->seqnum = oldtcpp->seqnum;
  1658.     tcpp->acknum = oldtcpp->acknum;
  1659.     tcpp->window = 0;
  1660. /*    tcpp->flags = intel16( oldflags ); */
  1661.     /* BUG FIX : jason dent found this thanks to SCO */
  1662.     tcpp->flags = intel16( (oldflags & 0x0fff ) | 0x5000 );
  1663.     tcpp->checksum = 0;
  1664.     tcpp->urgentPointer = 0;
  1665.  
  1666.     /* internet header */
  1667.     inp->ver = 4;
  1668.     inp->hdrlen = 5;
  1669.     inp->tos = his_ip->tos;
  1670.     inp->identification = intel16( ++ip_id );
  1671.     inp->frag = 0;
  1672.     inp->ttl = 254;
  1673.     inp->proto = TCP_PROTO;
  1674.     inp->checksum = 0;
  1675.     inp->source = his_ip->destination;
  1676.     inp->destination = his_ip->source;
  1677.  
  1678.     inp->checksum = ~checksum( inp, sizeof(in_Header))/* 0*/;
  1679.  
  1680.     /* compute tcp checksum */
  1681.     ph.src = inp->source;    /* already INTELled */
  1682.     ph.dst = inp->destination;
  1683.     ph.mbz = 0;
  1684.     ph.protocol = 6;
  1685.     ph.length = intel16( sendtotlen - sizeof(in_Header));
  1686.  
  1687.     ph.checksum = checksum(&pkt->tcp, sizeof(tcp_Header));
  1688.     tcpp->checksum =  ~checksum(&ph, sizeof(ph));
  1689.  
  1690.     if (_dbugxmit) (*_dbugxmit)(NULL,inp,tcpp,__LINE__);
  1691.     _eth_send( intel16( inp->length ));
  1692. }
  1693.  
  1694.  
  1695.  
  1696.  
  1697. /**********************************************************************
  1698.  * socket functions
  1699.  **********************************************************************/
  1700.  
  1701. /* socket based stuff */
  1702.  
  1703. /*
  1704.  * sock_read - read a socket with maximum n bytes
  1705.  *         - busywaits until buffer is full but calls s->usr_yield
  1706.  *         - returns count also when connection gets closed
  1707.  */
  1708. sock_read(sock_type *s, byte *dp, int len )
  1709. {
  1710.     int templen, count;
  1711.     count = 0;
  1712.     do {
  1713.     if ( s->udp.ip_type == UDP_PROTO )
  1714.             templen = udp_read( s, dp, len );
  1715.     else
  1716.         templen = tcp_read( s, dp, len);
  1717.         if (s->tcp.usr_yield) (s->tcp.usr_yield)();
  1718.         if (templen < 1 ) {
  1719.             if (!tcp_tick( s )) return( count );
  1720.         } else {
  1721.             count += templen;
  1722.             dp += templen;
  1723.             len -= templen;
  1724.         }
  1725.     } while ( len );
  1726.     return( count );
  1727. }
  1728. /*
  1729.  * sock_fead - read a socket with maximum n bytes
  1730.  *         - does not busywait until buffer is full
  1731.  */
  1732. sock_fastread(sock_type *s, byte *dp, int len )
  1733. {
  1734.     if ( s->udp.ip_type == UDP_PROTO )
  1735.     len = udp_read( s, dp, len );
  1736.     else
  1737.     len = tcp_read( s, dp, len);
  1738.     return( len );
  1739. }
  1740.  
  1741.  
  1742. /*
  1743.  * sock_write - writes data and returns length written
  1744.  *          - does not perform flush
  1745.  *          - repeatedly calls s->usr_yield
  1746.  */
  1747.  
  1748. sock_write(sock_type *s, byte *dp, int len)
  1749. {
  1750.     int offset, oldlen, oldmode, proto;
  1751.  
  1752.     oldlen = len;
  1753.     offset = 0;
  1754.  
  1755.     proto = (s->udp.ip_type == TCP_PROTO);
  1756.     if ( proto ) oldmode = s->tcp.flags & tcp_FlagPUSH;
  1757.     while ( len  > 0) {
  1758.         if (proto) {
  1759.             s->tcp.flags |= oldmode;
  1760.             offset += tcp_Write( s, &dp[ offset ], len);
  1761.         } else
  1762.         offset += udp_Write( s, &dp[ offset ], len );
  1763.     len = oldlen - offset;
  1764.     if (s->udp.usr_yield)(s->udp.usr_yield)();
  1765.     if (!tcp_tick(s)) return( 0 );
  1766.     }
  1767.     return( oldlen );
  1768. }
  1769.  
  1770.  
  1771.  
  1772. sock_fastwrite(sock_type *s, byte *dp, int len)
  1773. {
  1774.     return( ( s->udp.ip_type == UDP_PROTO ) ?
  1775.     udp_Write( s, dp, len ) :
  1776.     tcp_Write( s, dp, len) );
  1777. }
  1778.  
  1779. int sock_setbuf( sock_type *s, byte *dp, int len )
  1780. {
  1781.     if ( len < 0 ) return( 0 );
  1782.     if (len == 0 || dp == NULL ) {
  1783.         s->tcp.rdata = s->tcp.rddata;
  1784.         s->tcp.maxrdatalen = tcp_MaxBufSize;
  1785.     } else {
  1786.         s->tcp.rdata = dp;
  1787.         s->tcp.maxrdatalen = len;
  1788.     }
  1789.     return( s->tcp.maxrdatalen);
  1790. }
  1791.  
  1792. int sock_enqueue(sock_type *s, byte *dp, int len )
  1793. {
  1794.     int written;
  1795.  
  1796.     if ( len < 0 ) return( 0 );
  1797.     if ( s->udp.ip_type == UDP_PROTO ) {
  1798.         do {
  1799.             written = udp_Write( s, dp, len );
  1800.             dp += written;
  1801.         } while (len -= written > 0);
  1802.     } else {
  1803.         s->tcp.queue = dp;
  1804.         s->tcp.queuelen = len;
  1805.         s->tcp.datalen = len;
  1806.         tcp_send( s, __LINE__ );  /* start sending it */
  1807.     }
  1808.     return( len );
  1809. }
  1810.  
  1811.  
  1812. sock_flush( sock_type *s )
  1813. {
  1814.     if ( s->tcp.ip_type == TCP_PROTO )
  1815.     tcp_Flush( s );
  1816. }
  1817.  
  1818. /*
  1819.  * sock_flushnext - cause next transmission to have a flush
  1820.  */
  1821. sock_flushnext( sock_type *s)
  1822. {
  1823.     if (s->tcp.ip_type == TCP_PROTO )
  1824.     s->tcp.flags |= tcp_FlagPUSH;
  1825. }
  1826. /*
  1827.  * sock_putc - put a character
  1828.  *         - no expansion but flushes on '\n'
  1829.  *         - returns character
  1830.  */
  1831. byte sock_putc( sock_type *s, byte c )
  1832. {
  1833.     if (( c == '\n') || ( c == '\r'))
  1834.     sock_flushnext( s );
  1835.     sock_write( s, &c, 1 );
  1836.     return( c );
  1837. }
  1838.  
  1839. word sock_getc( sock_type *s )
  1840. {
  1841.     char ch;
  1842.     return( sock_read( s, &ch, 1 ) < 1 ? EOF : ch );
  1843. }
  1844.  
  1845. /*
  1846.  * sock_puts - does not append carriage return in binary mode
  1847.  *         - returns length
  1848.  */
  1849. sock_puts( sock_type *s, byte *dp )
  1850. {
  1851.     int len, oldmode;
  1852.  
  1853.     len = strlen( dp );
  1854.  
  1855.     if (s->tcp.sock_mode & TCP_MODE_ASCII ) {
  1856.         if (s->tcp.ip_type == TCP_PROTO )
  1857.             s->tcp.sock_mode |= TCP_LOCAL;
  1858.         if (len) sock_write( s, dp, len );
  1859.         sock_flushnext( s );
  1860.         sock_write( s, "\r\n", 2 );
  1861.     } else {
  1862.         sock_flushnext( s );
  1863.         sock_write( s, dp, len );
  1864.     }
  1865.     return( len );
  1866. }
  1867.  
  1868. /*
  1869.  * sock_update - update the socket window size to the other guy
  1870.  */
  1871. static sock_update( tcp_Socket *s )
  1872. {
  1873.     if (s->ip_type == TCP_PROTO) {
  1874.         if ( !s->rdatalen )
  1875.             tcp_send( s, __LINE__ );              /* update the window */
  1876.     else
  1877.         tcp_sendsoon( s );
  1878.     }
  1879. }
  1880. /*
  1881.  * sock_gets - read a string from any socket
  1882.  *         - return length of returned string
  1883.  *           - removes end of line terminator(s)
  1884.  */
  1885. word sock_gets( sock_type *s, byte *dp, int n )
  1886. {
  1887.     int len, templen;
  1888.     char *src_p, *temp, *temp2;
  1889.     char *endn, *endr;        /* used since we do not list strpbrk */
  1890.     int *np;
  1891.     
  1892.     char *src, *dest, *tempp;
  1893.  
  1894.     if ( s->udp.ip_type == UDP_PROTO ) {
  1895.     src_p = s->udp.rdata;
  1896.     np = &s->udp.rdatalen;
  1897.     } else {
  1898.     src_p = s->tcp.rdata;
  1899.     np = &s->tcp.rdatalen;
  1900.     }
  1901.     if ( !*np ) return( 0 );
  1902.  
  1903.     /* eat trailing \n or \0 from previous line */
  1904.     if ( *src_p == 0 || *src_p == '\n' ) {
  1905.         movmem( src_p + 1, src_p, *np -= 1 );
  1906.         if ( !*np ) return( 0 );
  1907.     }
  1908.  
  1909.     if ( --n > *np ) n = *np;
  1910.  
  1911.     /* src_p[ *np ] = 0; terminate string */
  1912.     strncpy( dp, src_p, n );    /* copy everything */
  1913.     dp[ n ] = 0;                /* terminate */
  1914.  
  1915.     temp = strchr( dp, '\n');
  1916.     temp2= strchr( dp, '\r');
  1917.  
  1918.     if (temp)  *temp = 0;
  1919.     if (temp2) *temp2= 0;
  1920.  
  1921.     len = strlen( dp );
  1922.  
  1923.     /* skip if there were no crs */
  1924.     if ( !temp2 ) {
  1925.         *dp = 0;
  1926.  
  1927.         return( 0 );
  1928.     }
  1929. #ifdef OLD
  1930.     /* skip over \n and \r but stop on end */
  1931.     if ( temp ) templen = FP_OFF( temp ) - FP_OFF( dp );
  1932.     else if ( temp2 ) templen = FP_OFF( temp2 ) - FP_OFF( dp );
  1933.     else templen = len + 1;
  1934.  
  1935.     if (temp || temp2 ) {
  1936.         ++templen;
  1937.         movmem( &src_p[ templen ], src_p, *np -= templen);
  1938.     } else
  1939.         * np = 0;
  1940. #else
  1941.     /* expect \r\n or \r\0 or \n or \r */
  1942.     /* so get first of the two */
  1943.  
  1944.     if ( temp == NULL ) {       /* handles \r only */
  1945.         temp = temp2;
  1946.         temp2 = NULL;
  1947.     } else if ( FP_OFF( temp ) > FP_OFF( temp2 ))
  1948.         temp = temp2;           /* handles trailing \n or \0 */
  1949.  
  1950.     n = len + 1;                /* account for first \r */
  1951. #ifdef OLD
  1952.     if ( temp2 && temp[1] == 0 ) n++;   /* account for \0, \n, etc */
  1953. #else
  1954.     /* we check next char if it exists, and skip it if 0, \r, or \n */
  1955.     if ((*np > n) && !src_p[n] ) n++;
  1956. #endif /* OLD */
  1957.     movmem( &src_p[ n ], src_p, *np -= n );
  1958.     if (*np < 0) *np = 0;
  1959. #endif /* OLD */
  1960.  
  1961.     sock_update( s );   /* new window */
  1962.     return( len );
  1963. }
  1964.  
  1965.  
  1966. /*
  1967.  * sock_dataready - returns number of bytes waiting to be ready
  1968.  *          - if in ASCII mode, return 0 until a line is present
  1969.  *            or the buffer is full
  1970.  */
  1971. word sock_dataready( sock_type *s )
  1972. {
  1973.     int len;
  1974.     char *p;
  1975.  
  1976.     if (!(len = s->tcp.rdatalen)) return( 0 );
  1977.  
  1978.     if ( s->tcp.sock_mode & TCP_MODE_ASCII ) {
  1979.         p = s->tcp.rdata;
  1980.         if ( *p == '\n' ) {
  1981.             movmem( p + 1, p, s->tcp.rdatalen = --len);
  1982.             if ( ! len ) return( 0 );
  1983.         }
  1984.         /* check for terminating \r */
  1985.         if ( memchr( p, '\r', len))
  1986.             return( len );
  1987.         return( 0 );
  1988.     } else
  1989.         return( len );
  1990. }
  1991.  
  1992. sock_established( sock_type *s )
  1993. {
  1994.     switch ( s->tcp.ip_type ) {
  1995.     case UDP_PROTO :
  1996.         return( 1 );
  1997.     case TCP_PROTO :
  1998.                 return( s->tcp.state == tcp_StateESTAB ||
  1999.                         s->tcp.state == tcp_StateESTCL ||
  2000.                         s->tcp.state == tcp_StateCLOSWT );
  2001.     default :
  2002.         return( 0 );
  2003.     }
  2004. }
  2005.  
  2006. sock_close( s )
  2007. sock_type *s;
  2008. {
  2009.     switch (s->udp.ip_type) {
  2010.     case UDP_PROTO :
  2011.         udp_close( s );
  2012.         break;
  2013.     case TCP_PROTO :
  2014.         tcp_close( s );
  2015.         tcp_tick( s );
  2016.         break;
  2017.     }
  2018. }
  2019.  
  2020.  
  2021. /*
  2022.  * _ip_delay0 called by macro sock_wait_established()
  2023.  * _ip_delay1 called by macro sock_wait_intput()
  2024.  * _ip_delay2 called by macro sock_wait_closed();
  2025.  *
  2026.  */
  2027.  
  2028. _ip_delay0( s, timeoutseconds, fn, statusptr )
  2029. sock_type *s;
  2030. int timeoutseconds;
  2031. procref fn;
  2032. int *statusptr;
  2033. {
  2034.     int status;
  2035.     ip_timer_init( s , timeoutseconds );
  2036.     do {
  2037.     if ( s->tcp.ip_type == TCP_PROTO ) {
  2038.         if ( tcp_established( s )) {
  2039.         status = 0;
  2040.         break;
  2041.         }
  2042.     }
  2043.     kbhit();    /* permit ^c */
  2044.     if ( !tcp_tick( s )) {
  2045.              if (!s->tcp.err_msg) s->tcp.err_msg = "Host refused connection";
  2046.          status = -1;    /* get an early reset */
  2047.          break;
  2048.     }
  2049.     if ( ip_timer_expired( s )) {
  2050.             s->tcp.err_msg = "Open timed out";
  2051.             sock_close( s );
  2052.         status = -1;
  2053.         break;
  2054.     }
  2055.     if ( fn ) if (status = fn(s)) break;
  2056.     if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2057.     if ( s->tcp.ip_type == UDP_PROTO ) {
  2058.         status = 0;
  2059.         break;
  2060.     }
  2061.     } while ( 1 );
  2062.     if (statusptr) *statusptr = status;
  2063.     return( status );
  2064. }
  2065.  
  2066. _ip_delay1( s, timeoutseconds, fn, statusptr)
  2067. sock_type *s;
  2068. int timeoutseconds;
  2069. procref fn;
  2070. int *statusptr;
  2071. {
  2072.     int status;
  2073.     ip_timer_init( s , timeoutseconds );
  2074.  
  2075.     sock_flush( s );    /* new enhancement */
  2076.  
  2077.     do {
  2078.     if ( sock_dataready( s )) {
  2079.         status = 0;
  2080.         break;
  2081.     }
  2082.     kbhit();    /* permit ^c */
  2083.  
  2084.     if ( !tcp_tick( s )) {
  2085.         status = 1;
  2086.         break;
  2087.     }
  2088.     if ( ip_timer_expired( s )) {
  2089.             s->tcp.err_msg = "Connection timed out";
  2090.             sock_close( s );
  2091.         status = -1;
  2092.         break;
  2093.     }
  2094.     if (fn) {
  2095.         if (status = fn(s))
  2096.         break;
  2097.     }
  2098.     if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2099.     } while ( 1 );
  2100.     if (statusptr) *statusptr = status;
  2101.     return( status );
  2102. }
  2103.  
  2104. _ip_delay2( s, timeoutseconds, fn, statusptr)
  2105. sock_type *s;
  2106. int timeoutseconds;
  2107. procref fn;
  2108. int *statusptr;
  2109. {
  2110.     int status;
  2111.     ip_timer_init( s , timeoutseconds );
  2112.  
  2113.     if (s->tcp.ip_type != TCP_PROTO ) return( 1 );
  2114.  
  2115.     do {
  2116.         /* in this situation we KNOW user not planning to read rdata */
  2117.         s->tcp.rdatalen = 0;
  2118.     kbhit();    /* permit ^c */
  2119.     if ( !tcp_tick( s )) {
  2120.         status = 1;
  2121.         break;
  2122.     }
  2123.     if ( ip_timer_expired( s )) {
  2124.             s->tcp.err_msg = "Connection timed out";
  2125.         sock_abort( s );
  2126.         status = -1;
  2127.         break;
  2128.     }
  2129.     if (fn) {
  2130.         if (status = fn(s))
  2131.         break;
  2132.     }
  2133.     if ( s->tcp.usr_yield ) (*s->tcp.usr_yield)();
  2134.  
  2135.     } while ( 1 );
  2136.     if (statusptr) *statusptr = status;
  2137.     return( status );
  2138. }
  2139.  
  2140.  
  2141. char *rip( char *s )
  2142. {
  2143.     char *temp;
  2144.  
  2145.     if (temp = strchr( s, '\n')) *temp = 0;
  2146.     if (temp = strchr( s, '\r')) *temp = 0;
  2147.     return( s );
  2148. }
  2149.  
  2150.