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