home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / DataScope 2.0.3 / DataScope2l / TCPSource / tools.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  13.4 KB  |  548 lines  |  [TEXT/MPS ]

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