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