home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / tel_2_2_ / source / tools.c < prev    next >
C/C++ Source or Header  |  1988-07-15  |  15KB  |  563 lines

  1. /*
  2. *      TOOLS.C
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/IP kernel for NCSA Telnet                                       *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. ****************************************************************************
  16. *
  17. *  Portions of the driver code that are not specific to a particular protocol
  18. *
  19. */
  20. #include "stdio.h"
  21. #include "protocol.h"
  22. #include "data.h"
  23.  
  24.  
  25. /************************************************************************/
  26. /*  netsleep
  27. *      sleep, while demuxing packets, so we don't miss anything
  28. *
  29. */
  30. netsleep(n)
  31.     int n;
  32.     {
  33.     int i,nmux,redir;
  34.     int32 t,gt,start;
  35.     struct port *p;
  36.     uint8 *pc;
  37.  
  38.     redir = 0;
  39.     start = time(NULL);
  40.  
  41.     if (n)
  42.         t = start + n*TICKSPERSEC;
  43.     else
  44.         t = start;
  45.  
  46.     do {
  47.         nmux = demux(1);                /* demux all packets */
  48.  
  49. /*
  50. *  if there were packets in the incoming packet buffer, then more might
  51. *  have arrived while we were processing them.  This gives absolute priority
  52. *  to packets coming in from the network.
  53. */
  54.         if (nmux)
  55.             continue;
  56. /*
  57. *  Check for any ICMP redirect events.
  58. */
  59.         if (IREDIR == netgetevent(ICMPCLASS,&i,&i))
  60.             redir = 1;
  61. /*
  62. *  Check each port to see if action is necessary.
  63. *  This now sends all Ack packets, due to p->lasttime being set to 0L.
  64. *  Waiting for nmux == 0 for sending ACKs makes sure that the network
  65. *  has a much higher priority and reduces the number of unnecessary ACKs.
  66. */
  67.         gt = time(NULL);
  68.  
  69.         for (i=0; i < NPORTS; i++) {
  70.             p = portlist[i];
  71.             if ((p != NULL) && (p->state > SLISTEN)) {
  72.  
  73.                 if (!p->out.lasttime) 
  74.                     transq(p);                /* takes care of all ACKs */
  75.  
  76.                 else if ((p->out.contain > 0) || (p->state > SEST)) {
  77. /*
  78. *  if a retransmission timeout occurs, exponential back-off.
  79. *  This number returns toward the correct value by the RTT measurement
  80. *  code in ackcheck.
  81. *
  82. *  fix: 5/12/88, if timer was at MAXRTO, transq didn't get hit - TK
  83. */
  84.                     if ((p->out.lasttime + p->rto < gt)) {
  85.                         if (p->rto < MAXRTO) 
  86.                             p->rto <<= 1;        /* double it */
  87.                         transq(p);
  88.                     }
  89.                 }
  90.  
  91.                 if ((p->out.lasttime + POKEINTERVAL < gt) && 
  92.                     (p->state == SEST))
  93.                     transq(p);
  94. /*
  95. *  check to see if ICMP redirection occurred and needs servicing.
  96. *  If it needs servicing, try to get the new hardware address for the new 
  97. *  gateway.  If getdlayer fails, we assume an ARP was sent, another ICMP
  98. *  redirect will occur, this routine will reactivate, and then the hardware
  99. *  address will be available in the cache.
  100. *  Check all ports to see if they match the redirected address.
  101. */
  102.                 if (redir && comparen(p->tcpout.i.ipdest,nnicmpsave,4)) {
  103.                     pc = getdlayer(nnicmpnew);
  104.                     if (pc != NULL)
  105.                         movebytes(p->tcpout.d.dest,pc,DADDLEN);
  106.                 }
  107.             }
  108.         }
  109.         redir = 0;                /* reset flag for next demux */
  110.  
  111.     } while ((t > time(NULL))         /* done yet? */
  112.         && (time(NULL) >= start));  /* allow for wraparound of timer */
  113.  
  114.  
  115.     return(nmux);                /* will demux once, even for sleep(0) */
  116.  
  117. }
  118.  
  119. /***************************************************************************/
  120. /*  enqueue
  121. *   add something to a TCP queue.  Used by both 'write()' and tcpinterpret
  122. *   WINDOWSIZE is the size limitation of the advertised window.
  123. */
  124. enqueue(wind,buffer,nbytes)
  125.     struct window *wind;
  126.     char *buffer;
  127.     int nbytes;
  128.     {
  129.     int i;
  130.  
  131.     i = WINDOWSIZE - wind->contain;
  132.     if (i <= 0 || nbytes == 0)
  133.         return(0);                        /* no room at the inn */
  134.  
  135.     if (nbytes > i)
  136.         nbytes = i;
  137.  
  138.     i = wind->where - wind->endlim;        /* room at end */
  139.     i += WINDOWSIZE;
  140.  
  141.     if (i < nbytes) {
  142.         movebytes(wind->endlim,buffer,i);
  143.         movebytes(wind->where,(char *)(buffer+i),nbytes-i);
  144.         wind->endlim = wind->where + nbytes - i;
  145.     } 
  146.     else {
  147.         movebytes(wind->endlim,buffer,nbytes);        /* fits in one chunk */
  148.         wind->endlim += nbytes;
  149.     }
  150.     wind->contain += nbytes;            /* more stuff here */
  151.  
  152.     return(nbytes);
  153.  
  154. }
  155.  
  156. /*************************************************************************/
  157. /* dequeue
  158. *     used by read, this copies data out of the queue and then
  159. *  deallocates it from the queue.
  160. *  cpqueue and rmqueue are very similar and are to be used by tcpsend
  161. *  to store unacknowledged data.
  162. *
  163. *  returns number of bytes copied from the queue
  164. */
  165. dequeue(wind,buffer,nbytes)
  166.     struct window *wind;
  167.     char *buffer;
  168.     int nbytes;                /* maximum number to copy out */
  169.     {
  170.     int i;
  171.  
  172.     if (wind->contain == 0)
  173.         return(0);
  174.  
  175.     if (wind->contain < nbytes)
  176.         nbytes = wind->contain;
  177.  
  178.     i = wind->endbuf - wind->base;
  179.  
  180.     if (i <= nbytes) {
  181.         movebytes(buffer,wind->base,i);
  182.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  183.         wind->base = wind->where + nbytes-i;
  184.     }
  185.     else {
  186.         movebytes( buffer, wind->base, nbytes);
  187.         if (wind->contain == nbytes) 
  188.             wind->base = wind->endlim = wind->where;
  189.         else
  190.             wind->base += nbytes;
  191.     }
  192.     
  193.     wind->contain -= nbytes;
  194.  
  195.     return(nbytes);
  196.  
  197. }
  198.  
  199. #ifdef notneeded
  200. /**************************************************************************/
  201. /*  cpqueue
  202. *       does the same thing as dequeue, but does not deallocate the data
  203. *   used when transmitting TCP data.  When the data is ACKed, then 
  204. *   rmqueue is called to deallocate the correct amount of data.
  205. */
  206. cpqueue(wind,buffer,nbytes)
  207.     struct window *wind;
  208.     char *buffer;
  209.     int nbytes;                /* maximum number to copy out */
  210.     {
  211.     int i;
  212.  
  213.     if (wind->contain == 0)
  214.         return(0);
  215.  
  216.     if (wind->contain < nbytes)
  217.         nbytes = wind->contain;
  218.  
  219.     i = wind->endbuf - wind->base;
  220.  
  221.     if (i < nbytes) {
  222.         movebytes(buffer,wind->base,i);
  223.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  224.     }
  225.     else 
  226.         movebytes( buffer, wind->base, nbytes);
  227.     
  228.     return(nbytes);
  229.  
  230. }
  231. #endif
  232.  
  233. /**************************************************************************/
  234. /*  rmqueue
  235. *     does the queue deallocation that is left out of cpqueue
  236. *
  237. *   rmqueue of WINDOWSIZE or greater bytes will empty the queue
  238. */
  239. rmqueue(wind,nbytes)
  240.     struct window *wind;
  241.     int nbytes;                    /* number to remove */
  242.     {
  243.     int i;
  244.  
  245.     if (wind->contain < nbytes)
  246.         nbytes = wind->contain;
  247.  
  248.     i = wind->endbuf - wind->base;
  249.  
  250.     if (i <= nbytes) 
  251.         wind->base = wind->where+nbytes-i;
  252.     else {
  253.         if (wind->contain == nbytes)
  254.             wind->base = wind->endlim = wind->where;
  255.         else
  256.             wind->base += nbytes;
  257.     }
  258.     
  259.     wind->contain -= nbytes;
  260.  
  261.     return(nbytes);
  262.  
  263. }
  264.  
  265.  
  266. /************************************************************************/
  267. /*  transq
  268. *
  269. *   Needed for TCP, not as general as cpqueue, 
  270. *   but is required for efficient transmit of the whole window.
  271. *
  272. *   Transmit the entire queue (window) to the other host without expecting
  273. *   any sort of acknowledgement.
  274. *
  275. */
  276. transq(prt)
  277.     struct port *prt;
  278.     {
  279.     uint bites;
  280.     int i,j,n;
  281.     struct window *wind;
  282.     uint32 saveseq;
  283.     uint8 *endb,*whereb,*baseb;
  284.  
  285.     if (prt == NULL) {
  286.         nnerror(406);        /* NULL port for trans */
  287.         return(-1);
  288.     }
  289.  
  290.     wind = &prt->out;
  291. /*
  292. *   find out how many bytes the other side will allow us to send (window)
  293. */
  294.     bites = wind->size;
  295.     if (wind->contain < bites)
  296.         bites = wind->contain;
  297.  
  298. /*
  299. *  set up the tcp packet for this, ACK field is same for all packets
  300. */
  301.     prt->tcpout.t.ack = longswap(prt->in.nxt);
  302. /*
  303. *  any more flags should be set?
  304. */
  305.     if (wind->push)                    /* is push indicator on? */
  306.         prt->tcpout.t.flags |= TPUSH;
  307.  
  308.     if ((bites <= 0) || prt->state != SEST) {    /* if no data to send . . . */
  309.         tcpsend(prt,0);                /* just a retransmission or ACK */
  310.         return(0);
  311.     }
  312.  
  313. /*
  314. *  we have data to send, get the correct sequence #'s 
  315. *  To be really real, we should check wraparound sequence # in the loop.
  316. */
  317.     saveseq = wind->nxt;
  318.  
  319.     whereb = wind->where;
  320.     endb = wind->endbuf;
  321.     baseb = wind->base;
  322. /*
  323. *  in a loop, transmit the entire queue of data 
  324. */
  325.     for (i=0 ; i < bites; i += prt->sendsize) {
  326.         n = prt->sendsize;
  327.         if (i + n > bites)
  328.             n = bites - i;
  329.  
  330.         j = endb - baseb;
  331.  
  332.         if (j < n) {
  333.             movebytes(prt->tcpout.x.data,baseb,j);
  334.             movebytes((char *)(prt->tcpout.x.data+j),whereb,n-j);
  335.             baseb = whereb + n-j;
  336.         }
  337.         else {
  338.             movebytes( prt->tcpout.x.data, baseb, n);
  339.             baseb += n;
  340.         }
  341.  
  342.         tcpsend(prt,n);                        /* send it */
  343.         wind->nxt += n;
  344.     }
  345.  
  346.     wind->nxt = saveseq;                    /* get back first seq # */
  347.  
  348.     return(0);
  349. }
  350.  
  351. /************************************************************************/
  352. /* comparen
  353. *  Take n bytes and return identical (true=1) or not identical (false=0)
  354. *
  355. *  Could be written in assembler for improved performance
  356. */
  357. comparen(s1,s2,n) 
  358.     uint8 *s1,*s2;
  359.     register int n;
  360.     {
  361.  
  362.     while (n--)
  363.         if (*s1++ != *s2++)
  364.             return(0);
  365.  
  366.     return(1);
  367.  
  368. }
  369.  
  370. /************************************************************************/
  371. /*  netposterr
  372. *   place an error into the event q
  373. *   Takes the error number and puts it into the error structure
  374. */
  375. netposterr(num)
  376.     int num;
  377.     {
  378.  
  379.     if (netputevent(ERRCLASS,ERR1,num))
  380.  
  381.         netputuev(ERRCLASS,ERR1,501);            /* only if we lost an event */
  382. }
  383.  
  384. /***********************************************************************/
  385. /*  netgetevent
  386. *   Retrieves the next event (and clears it) which matches bits in
  387. *   the given mask.  Returns the event number or -1 on no event present.
  388. *   Also returns the exact class and the associated integer in reference
  389. *   parameters.
  390. *
  391. *   The way the queue works:
  392. *     There is always a dummy record pointed to by nnelast.
  393. *     When data is put into the queue, it goes into nnelast, then nnelast
  394. *        looks around for another empty one to obtain.
  395. *        It looks at nnefree first, then bumps one from nnefirst if necessary.
  396. *     When data is retrieved, it is searched from nnefirst to nnelast.
  397. *        Any freed record is appended to nnefree.
  398. */
  399. netgetevent(mask,retclass,retint)
  400.     uint8 mask;
  401.     int *retclass,*retint;
  402.     {
  403.     int i,j;
  404.  
  405.     i = nnefirst;
  406.  
  407.     while (i != nnelast) {
  408.         if (mask & nnq[i].eclass) {
  409.             if (i == nnefirst) 
  410.                 nnefirst = nnq[nnefirst].next;        /* step nnefirst */
  411.             else 
  412.                 nnq[j].next = nnq[i].next;            /* bypass record i */
  413.  
  414.             nnq[i].next = nnefree;
  415.             nnefree = i;                            /* install in free list */
  416.             *retint = nnq[i].idata;
  417.             *retclass = nnq[i].eclass;
  418.             return(nnq[i].event);
  419.         }
  420.         j = i;
  421.         i = nnq[i].next;
  422.     }
  423.  
  424.     return(0);
  425.  
  426. }
  427.  
  428. /***********************************************************************/
  429. /*  netputevent
  430. *   add an event to the queue.
  431. *   Will probably get the memory for the entry from the free list.
  432. *   Returns 0 if there was room, 1 if an event was lost.
  433. */
  434. netputevent(class,what,dat)
  435.     int class,what,dat;
  436.     {
  437.     int i;
  438.  
  439.     i = nnelast;
  440.     nnq[i].eclass = class;                    /* put data in */
  441.     nnq[i].event = what;
  442.     nnq[i].idata = dat;
  443.  
  444.     if (nnefree >= 0) {                        /* there is a spot in free list */
  445.         nnq[i].next = nnelast = nnefree;
  446.         nnefree = nnq[nnefree].next;        /* remove from free list */
  447.         return(0);
  448.     }
  449.     else {
  450.         nnq[i].next = nnelast = nnefirst;
  451.         nnefirst = nnq[nnefirst].next;        /* lose oldest event */
  452.         return(1);
  453.     }
  454. }
  455.  
  456. /***************************************************************************/
  457. /*  netputuev
  458. *   put a unique event into the queue
  459. *   First searches the queue for like events
  460. */
  461. netputuev(class,what,dat)
  462.     int class,what,dat;
  463.     {
  464.     int i;
  465.  
  466.     i = nnefirst;
  467.     while (i != nnelast) {
  468.         if (nnq[i].idata == dat && nnq[i].event == what &&
  469.             nnq[i].eclass == class)
  470.             return(0);
  471.         i = nnq[i].next;
  472.     }
  473.  
  474.     return(netputevent(class,what,dat));
  475.  
  476. }
  477.  
  478.  
  479. /************************************************************************/
  480. /*  neterrstring
  481. *   returns the string associated with a particular error number
  482. *
  483. *   error number is formatted %4d at the beginning of the string
  484. */
  485. static char *errs[] = {"   0 Error unknown",
  486.             " 100 Network jammed, probable break in wire",
  487.             " 101 Could not initialize hardware level network driver",
  488.             " 102 ERROR: The conflicting machine is using the same IP number",
  489.             " 103 RARP request failed, an IP number is required",
  490.             " 300 Bad IP checksum",
  491.             " 301 IP packet not for me",
  492.             " 302 IP packet with options received",
  493.             " 303 IP: unknown higher layer protocol",
  494.             " 304 IP: fragmented packet received, frags not supported",
  495.             " 400 TCP: bad checksum",
  496.             " 401 ACK invalid for TCP syn sent",
  497.             " 403 TCP in unknown state",
  498.             " 404 Invalid port for TCPsend",
  499.             " 405 TCP connection reset by other host",
  500.             " 406 Null port specified for ackandtrans",
  501.             " 407 Packet received for invalid port -- reset sent",
  502.             " 500 No internal TCP ports available",
  503.             " 501 Warning: Event queue filled, probably non-fatal",
  504.             " 504 Local host or gateway not responding",
  505.             " 505 Memory allocation error, cannot open port",
  506.             " 506 Not allowed to connect to broadcast address",
  507.             " 507 Reset received: syn sent, host is refusing connection",
  508.             " 600 ICMP:    Echo reply",
  509.             " 603 ICMP:    Destination unreachable",
  510.             " 604 ICMP:    Source Quench",
  511.             " 605 ICMP:    Redirect, another gateway is more efficient",
  512.             " 608 ICMP:    Echo requested (ping requested)",
  513.             " 611 ICMP:    Time Exceeded on Packet",
  514.             " 612 ICMP:    Parameter problem in IP",
  515.             " 613 ICMP:    Timestamp request",
  516.             " 614 ICMP:    Timestamp reply",
  517.             " 615 ICMP:    Information request",
  518.             " 616 ICMP:    Information reply",
  519.             " 699 ICMP: Checksum error",
  520.             " 700 Bad UDP checksum",
  521.             " 800 Domain: Name request to server failed",
  522.             " 801 Domain: Using default domain",
  523.             " 802 Domain: name does not exist",
  524.             " 803 Domain: UDP name server did not resolve the name",
  525.             " 804 Domain: name server failed, unknown reason",
  526.             " 805 Host machine not in configuration file",
  527.             " 806 Missing IP number, requires domain lookup",
  528.             " 900 Session: Cannot find or open configuration file",
  529.             " 901 Session: Cannot allocate memory for processing",
  530.             " 902 Session: Invalid keyword in configuration file",
  531.             " 903 Session: Element too long (>200), maybe missing quote",
  532.             " 904 Session: Probable missing quote marks, a field must be on one line",
  533.             " 905 Session: 'name' field required before other machine entries",
  534.             " 906 Session: Syntax error, invalid IP number",
  535.             " 907 Session: Syntax error, Subnet mask invalid",
  536.             " 908 Session: Syntax error, IP address for this PC is invalid",
  537.  
  538.                         ""};
  539.  
  540. static char errspace[80];        /* room for user-defined errors */
  541.  
  542. char *neterrstring(errno)
  543.     int errno;
  544.     {
  545.     int i;
  546.     char s[10];
  547.  
  548.     if (errno < 0) 
  549.         return(errspace);
  550.  
  551.     sprintf(s,"%4d",errno);
  552.     i = 0;
  553.     do {
  554.         if (!strncmp(errs[i],s,4))
  555.             return(errs[i]+5);            /* pointer to error message  */
  556.         i++;
  557.  
  558.     } while (*errs[i] || i > 100);            /* until NULL found */
  559.  
  560.     return(errs[0]+5);                    /* error unknown */
  561. }
  562.  
  563.