home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / contribu / byu_tel2.hqx / tcpip / user.c < prev    next >
Text File  |  1989-06-22  |  15KB  |  666 lines

  1. /*
  2. *  USER.C
  3. *  Network library interface routines
  4. *  Generally called by the session layer
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/IP kernel for NCSA Telnet                                       *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  18. *                                                                          *
  19. ****************************************************************************
  20. *  Revisions:
  21. *  10/87  Initial source release, Tim Krauskopf
  22. *  2/88  typedef support for other compilers (TK)
  23. *
  24. */
  25. #define MASTERDEF 1
  26. #include "stdio.h"
  27. #include "protocol.h"
  28. #include "data.h"
  29.  
  30. #define LOWWATER 600
  31.  
  32. /***************************************************************************/
  33. /*  netread
  34. *   Read from a connection buffer into a user buffer.  
  35. *   Returns number of bytes read, < 0 on error
  36. */
  37. netread(pnum,buffer,n)
  38.     int pnum,n;
  39.     char *buffer;
  40.     {
  41.     int howmany,i;
  42.     struct port *p;
  43.  
  44.     if (pnum < 0)            /* check validity */
  45.         return(-2);
  46.  
  47.     if (NULL == (p = portlist[pnum]))
  48.         return(-2);
  49.  
  50.     if (p->state != SEST) {                 /* foreign or netclose */
  51.         if (p->state == SCWAIT) {            /* ready for me to close my side? */
  52.             if (!p->in.contain) {
  53.                 p->tcpout.t.flags = TFIN | TACK;
  54.                 tcpsend(p,0);
  55.                 p->state = SLAST;
  56.                 return(-1);
  57.             }
  58.             /* else, still data to be read */
  59.         }
  60.         else
  61.             return(-1);
  62.     }
  63.  
  64.     howmany = dequeue(&p->in,buffer,n);            /* read from tcp buffer */
  65.  
  66.     i = p->in.size;                                /* how much before? */
  67.  
  68.     p->in.size += howmany;                        /* increment leftover room  */
  69.  
  70.     if (i < LOWWATER && p->in.size >= LOWWATER) /* we passed mark */
  71.         p->out.lasttime = 0L;
  72.  
  73.     if (p->in.contain)                            /* if still data to be read */
  74.         netputuev(CONCLASS,CONDATA,pnum);        /* don't forget it */
  75.  
  76.     return(howmany);
  77.  
  78. }
  79.  
  80. /************************************************************************/
  81. /* netwrite
  82. *  write something into the output queue, netsleep routine will come
  83. *  around and send the data, etc.
  84. *
  85. */
  86. netwrite(pnum,buffer,n)
  87.     int pnum,n;
  88.     char *buffer;
  89.     {
  90.     int nsent,before;
  91.     struct port *p;
  92.  
  93.     if (pnum < 0)
  94.         return(-2);
  95.  
  96.     p = portlist[pnum];
  97.  
  98.     if (p == NULL)
  99.         return(-2);
  100.  
  101.     if (p->state != SEST)            /* must be established connection */
  102.         return(-1);
  103.  
  104.     before = p->out.contain;
  105.  
  106.     nsent = enqueue(&p->out,buffer,n);
  107.  
  108.     if (!before)                    /* if this is something new, */
  109.         p->out.lasttime = 0L;        /* cause timeout to be true */
  110.  
  111.     return(nsent);
  112.  
  113. }
  114.  
  115. /**************************************************************************/
  116. /*  netpush
  117. *   attempt to push the rest of the data from the queue
  118. *   and then return whether the queue is empty or not (0 = empty)
  119. *   returns the number of bytes in the queue.
  120. */
  121. netpush(pnum)
  122.     int pnum;
  123.     {
  124.     struct port *p;
  125.  
  126.     if (pnum < 0)
  127.         return(-2);
  128.  
  129.     if (NULL == (p = portlist[pnum]))
  130.         return(-2);
  131.  
  132.     p->out.push = 1;
  133.  
  134.     return(p->out.contain);
  135.  
  136. }    
  137.  
  138. /**************************************************************************/
  139. /*  netqlen
  140. *   return the number of bytes waiting to be read from the incoming queue.
  141. */
  142. netqlen(pnum)
  143.     int pnum;
  144.     {
  145.  
  146.     if (portlist[pnum] == NULL)
  147.         return(-2);
  148.  
  149.     return(portlist[pnum]->in.contain);
  150.  
  151. }
  152.  
  153. /**************************************************************************/
  154. /*  netroom()
  155. *    return how much room is available in output buffer for a connection
  156. */
  157. netroom(pnum)
  158.     int pnum;
  159.     {
  160.  
  161.     if (portlist[pnum] == NULL || portlist[pnum]->state != SEST)
  162.         return(-2);
  163.  
  164.     return(WINDOWSIZE - portlist[pnum]->out.contain);
  165.  
  166. }
  167.  
  168. /**************************************************************************/
  169. /* netsegsize and neterrchange and netsetip and netgetip
  170. *
  171. *  set operating parameters to change them from the default values used.
  172. */
  173.  
  174. netsegsize(newsize)
  175.     int newsize;
  176.     {
  177.     int i;
  178.  
  179.     i = nnsegsize;
  180.     nnsegsize = newsize;
  181.  
  182.     return(i);
  183. }
  184.  
  185. netquench(newcredit)
  186.     int newcredit;
  187.     {
  188.     int i;
  189.  
  190.     i = nncredit;
  191.     nncredit = newcredit;
  192.  
  193.     return(i);
  194. }
  195.  
  196. netarptime(t)                    /* dlayer timeout in secs */
  197.     int t;
  198.     {
  199.     nndto = t;
  200. }
  201.  
  202. netsetip(st)
  203.     unsigned char *st;
  204.     {
  205. /*
  206. *  change all dependent locations relating to the IP number
  207. *  don't worry about open connections, they must be closed by higher layer
  208. */
  209.     movebytes(nnipnum,st,4);
  210.  
  211. /*    movebytes(arp.d.me,nnipnum,4);    this is a bug - not needed */
  212.  
  213.     movebytes(arp.spa,nnipnum,4);
  214.     movebytes(blankip.i.ipsource,nnipnum,4);
  215.     movebytes(ulist.tcps.source,nnipnum,4);
  216.     movebytes(ulist.udpout.i.ipsource,nnipnum,4);
  217.  
  218. }
  219.  
  220. netgetip(st)
  221.     unsigned char *st;
  222.     {
  223.     movebytes(st,nnipnum,4);
  224. }
  225.  
  226. netsetmask(st)
  227.     unsigned char *st;
  228.     {
  229.     movebytes(nnmask,st,4);
  230. }
  231.  
  232. netgetmask(st)
  233.     unsigned char *st;
  234.     {
  235.     movebytes(st,nnmask,4);
  236. }
  237.  
  238. netfromport(port)            /* next "open" will use this port */
  239.     int16 port;
  240.     {
  241.     nnfromport = port;
  242.  
  243. }
  244.  
  245. /**************************************************************************/
  246. /*  netest?
  247. *  is a particular session established yet?
  248. *  Returns 0 if the connection is in the established state.
  249. */
  250. netest(pn)
  251.     int pn;
  252.     {
  253.     struct port *p;
  254.  
  255.     if (pn < 0 || pn > NPORTS)
  256.         return(-2);
  257.  
  258.     if (NULL == (p = portlist[pn]))
  259.         return(-2);
  260.  
  261.     if (p->state == SEST)
  262.         return(0);
  263.  
  264.     else if (p->state == SCWAIT) {
  265.             if (!p->in.contain) {
  266.                 p->tcpout.t.flags = TFIN | TACK;
  267.                 tcpsend(p,0);
  268.                 p->state = SLAST;
  269.                 return(-1);
  270.             }
  271.             else 
  272.                 return(0);                /* still more data to be read */
  273.     }
  274.  
  275.     return(-1);
  276.  
  277. }
  278.  
  279. /**************************************************************************/
  280. /*  netlisten
  281. *   Listen to a TCP port number and make the connection automatically when
  282. *   the SYN packet comes in.  The TCP layer will notify the higher layers
  283. *   with a CONOPEN event.  Save the port number returned to refer to this
  284. *   connection.
  285. *
  286. *   usage:   portnum = netlisten(service);
  287. *            int service;
  288. *
  289. */
  290. netlisten(serv)
  291.     uint serv;
  292.     {
  293.     int    pnum;
  294.     struct port *prt;
  295.     uint16 nn;
  296.  
  297.     pnum = makeport();
  298.  
  299.     if (pnum < 0)
  300.         return(-2);
  301.  
  302.     if (NULL == (prt = portlist[pnum]))
  303.         return(-2);
  304.  
  305.     prt->in.port = serv;
  306.     prt->out.port = 0;                        /* accept any outside port #*/
  307.     prt->in.lasttime = time(NULL);            /* set time we started */
  308.  
  309.     prt->state = SLISTEN;
  310.     prt->credit = 512;                        /* default value until changed */
  311.     prt->tcpout.i.protocol = PROTTCP;
  312.     prt->tcpout.t.source = intswap(serv);    /* set service here too */
  313.  
  314. /*
  315. *  install maximum segment size which will be sent out in the first
  316. *  ACK-SYN packet
  317. */
  318.     prt->tcpout.x.options[0] = 2;
  319.     prt->tcpout.x.options[1] = 4;
  320.     /* install maximum segment size */
  321.     nn = intswap(nnsegsize);
  322.     movebytes(&prt->tcpout.x.options[2],&nn,2);
  323.  
  324.     return(pnum);
  325. }
  326.  
  327. /***********************************************************************/
  328. /*  netgetftp
  329. *  Provides the information that ftp needs to open a stream back to the
  330. *  originator of the command connection.  The other side's IP number
  331. *  and the port numbers to be used to calculate the default data connection
  332. *  number.  Returns values in an integer array for convenient use in 
  333. *  PORT commands.
  334. */
  335. netgetftp(a,pnum)
  336.     int a[];
  337.     int pnum;
  338.     {
  339.     struct port *p;
  340.     uint i;
  341.  
  342.     p = portlist[pnum];
  343.  
  344.     a[0] = p->tcpout.i.ipdest[0];
  345.     a[1] = p->tcpout.i.ipdest[1];
  346.     a[2] = p->tcpout.i.ipdest[2];
  347.     a[3] = p->tcpout.i.ipdest[3];
  348.     i = intswap(p->tcpout.t.source);
  349.     a[4] = i >> 8;
  350.     a[5] = i & 255;
  351.     i = intswap(p->tcpout.t.dest);
  352.     a[6] = i >> 8;
  353.     a[7] = i & 255;
  354.  
  355. }
  356.  
  357. /**************************************************************************/
  358. /*  netopen
  359. *   Netopen is a cheap way to open a connection without looking up any
  360. *   machine information.  Uses suitable default values for everything.
  361. */
  362. netopen(s,tport)
  363.     unsigned char *s;
  364.     uint tport;
  365.     {
  366.  
  367.     return(netxopen(s,tport,MINRTO,TSENDSIZE,DEFSEG,DEFWINDOW));
  368. }
  369.  
  370.  
  371. /**************************************************************************/
  372. /*  netxopen
  373. *   Open a network socket for the user.
  374. *
  375. */
  376. netxopen(machine,service,rto,mtu,mseg,mwin)
  377.     uint8 *machine;
  378.     uint service,rto,mtu,mseg,mwin;        /* unix service port number */
  379.     {
  380.     struct port *p;
  381.     int pnum,ret,i;
  382.     uint8 *pc,*hiset;
  383.  
  384. /*
  385. *  check the IP number and don't allow broadcast addresses.
  386. *
  387. *  If the AND of the original and the mask does not change the value then
  388. *  the host portion is all zeros.
  389. *  If the OR of the original and the inverse mask does not change the value
  390. *  then the host portion is all ones.
  391. */
  392.     ret = 0;                        /* assume all are the same */
  393.     for (i=0; i<4; i++)
  394.         if (machine[i] != (machine[i] & nnmask[i]))
  395.             ret = 1;
  396.  
  397.     if (!ret) {                        /* if all are the same, reject broadcast addr */
  398.         nnerror(506);
  399.         return(-4);
  400.     }
  401.     
  402.     ret = 0;
  403.     for (i=0; i<4; i++) 
  404.         if (machine[i] != (uint8)(machine[i] | (~nnmask[i])))
  405.             ret = 1;
  406.         
  407.     if (!ret) {                        /* if all are the same, reject broadcast addr */
  408.         nnerror(506);
  409.         return(-4);
  410.     }
  411.  
  412.     netsleep(0);                    /* make sure no waiting packets */
  413.     pnum = makeport();
  414.  
  415.     if (pnum < 0)
  416.         return(-3);
  417.  
  418.     p = portlist[pnum];                /* create a new port */
  419. /*
  420. *  make a copy of the ip number that we are trying for
  421. */
  422.     movebytes(p->tcpout.i.ipdest,machine,4);
  423.     movebytes(p->tcps.dest,machine,4);        /* pseudo header needs it */
  424.  
  425. /*
  426. *  get the hardware address for that host, or use the one for the gateway
  427. *  all handled by 'netdlayer' by ARPs.
  428. */
  429.     pc = netdlayer(machine);                /* we have ether? */
  430.  
  431.     if (pc == NULL) {                        /* cannot connect to local machine */
  432.         nnerror(504);
  433.         return(-2);
  434.     }
  435.  
  436.     movebytes(p->tcpout.d.dest,pc,DADDLEN);        /* load it up */
  437.  
  438. /*
  439. *   Add in machine specific settings for performance tuning
  440. */
  441.     if (rto > MINRTO)
  442.         p->rto = rto;            /* starting retrans timeout */
  443.     if (mtu < TMAXSIZE)            /* largest packet space we have */
  444.         p->sendsize = mtu;        /* maximum transmit size for that computer */
  445.     if (mwin < WINDOWSIZE)        /* buffer size is the limit */
  446.         p->credit = mwin;        /* most data that we can receive at once */
  447.  
  448. #ifdef MAC
  449.     if (nnemac) {
  450. #endif
  451. /*
  452. *   quick check to see if someone else is using your IP number
  453. *   Some boards receive their own broadcasts and cannot use this check.
  454. *   The Mac will only use this check if it is using EtherTalk.
  455. */
  456.         i = cachelook(nnipnum,0,0);                /* don't bother to ARP */
  457.         if (i >= 0)    {                /* if it is not -1, we are in trouble */
  458.             hiset = (uint8 *)arpc[i].hrd;
  459.             pc = neterrstring(-1);
  460.             sprintf(pc,"Conflict with Ethernet hardware address: %2x:%2x:%2x:%2x:%2x:%2x",
  461.             hiset[0],hiset[1],hiset[2],hiset[3],hiset[4],hiset[5]);
  462.             nnerror(-1);
  463.             nnerror(102);
  464.             netclose(pnum);
  465.             return(-3);
  466.         }
  467. #ifdef MAC
  468.     }
  469. #endif
  470.  
  471. /*
  472. *  make the connection, if you can, we will get an event notification later
  473. *  if it connects.  Timeouts must be done at a higher layer.
  474. */
  475.     ret = doconnect(pnum,service,mseg);
  476.  
  477.     return(ret);
  478. }
  479.  
  480. /**********************************************************************/
  481.  
  482. doconnect(pnum,service,mseg)
  483.     int service,pnum,mseg;
  484.     {
  485.     uint16 seg;
  486.     struct port *p;
  487.  
  488.     p = portlist[pnum];
  489.  
  490.     p->tcpout.i.protocol = PROTTCP;                /* this will be TCP socket */
  491.     p->tcpout.t.dest = intswap(service);        /* for example, telnet=23 */
  492.     p->out.port = service;                        /* service is same as port num*/
  493.     p->tcpout.t.flags = TSYN;                    /* want to start up sequence */
  494.     p->tcpout.t.ack = 0;                        /* beginning has no ACK */
  495.  
  496.     p->state = SSYNS;                            /* syn sent */
  497. /*
  498. *  install maximum segment size which will be sent out in the first
  499. *  ACK-SYN packet
  500. */
  501.     p->tcpout.x.options[0] = 2;
  502.     p->tcpout.x.options[1] = 4;
  503.     /* install maximum segment size */
  504.     seg = intswap(mseg);
  505.     movebytes(&p->tcpout.x.options[2],&seg,2);
  506.  
  507.     p->tcpout.t.hlen=96;                    /* include one more word in hdr */
  508.     tcpsend(p,4);                            /* send opening volley */
  509.     p->tcpout.t.hlen=80;                    /* normal hdr len */
  510.  
  511. /*    savenxt = p->out.nxt; */
  512.     p->out.nxt += 1;                        /* ack should be for next byte */
  513.  
  514.     return(pnum);                            /* do not wait for connect */
  515.  
  516. }
  517.  
  518. /*************************************************************************/
  519. /*  netopen2
  520. *   Send out repeat SYN on a connection which is not open yet
  521. *   Checks, and only sends one if needed.
  522. *   Returns 1 if the state is still SYNS and 0 if the connection has proceeded.
  523. *   The timing is all handled at a higher layer.
  524. */
  525. netopen2(pnum)
  526.     int pnum;
  527.     {
  528.     struct port *p;
  529.  
  530.     if (pnum < 0 || pnum > NPORTS)
  531.         return(-1);
  532.     if (NULL == (p = portlist[pnum]))
  533.         return(-2);
  534.  
  535.     if (p->state != SSYNS)
  536.             return(0);                /* done our job */
  537. /*
  538. *  The connection has not proceeded to further states, try retransmission
  539. */
  540.  
  541.     p->out.nxt--;
  542.     p->tcpout.t.hlen=96;        /* include one more word in hdr */
  543.     tcpsend(p,4);                /* try sending again */
  544.     p->tcpout.t.hlen=80;            /* normal hdr len */
  545.     p->out.nxt++;
  546.  
  547.     return(1);
  548. }
  549.  
  550. /**************************************************************************/
  551. /* netclose
  552. *  Do appropriate actions to return connection state to SCLOSED which
  553. *  enables the memory for that port to be reused.
  554. */
  555. netclose(pnum)
  556.     int pnum;
  557.     {
  558.     struct port *p;
  559.  
  560.     if (pnum < 0 || pnum > NPORTS)            /* is a valid port? */
  561.         return(-1);
  562.  
  563.     if ((p = portlist[pnum]) != NULL) {            /* something there */
  564.         switch (p->state) {
  565.             case SLISTEN:                /* we don't care anymore */
  566.             case SSYNS:
  567.                 p->state = SCLOSED;
  568.                 break;
  569.             case SEST:                    /* must initiate close */
  570.                 /* send FIN */
  571.                 p->tcpout.t.flags = TACK | TFIN;
  572.                 tcpsend(p,0);
  573.                 p->state = SFW1;            /* wait for ACK of FIN */
  574.                 break;                        /* do nothing for now ?*/
  575.  
  576.             case SCWAIT:                    /* other side already closed */
  577.                 p->tcpout.t.flags = TFIN | TACK;
  578.                 tcpsend(p,0);
  579.                 p->state = SLAST;
  580.                 break;
  581.  
  582.             case STWAIT:                    /* time out yet? */
  583.                 if (portlist[pnum]->out.lasttime + WAITTIME < time(NULL)) 
  584.                     p->state = SCLOSED;
  585.                 break;
  586.  
  587.             case SLAST:                    /* five minute time out */
  588.                 if (portlist[pnum]->out.lasttime + LASTTIME < time(NULL)) 
  589.                     p->state = SCLOSED;
  590.                 break;
  591.             default:
  592.                 break;
  593.         }
  594.     }
  595.     else
  596.         return(1);
  597.  
  598.  
  599.     return(0);
  600. }
  601.  
  602. /**************************************************************************/
  603. /*  netinit
  604. *   Calls all of the various initialization routines that set up queueing
  605. *   variables, static values, reads configuration files, etc.
  606. */
  607.  
  608. netinit()
  609.     {
  610.     int ret;
  611.  
  612. /*
  613. *   Initializes all buffers and hardware for data link layer.
  614. *   Machine/board dependent.
  615. */
  616.     ret = dlayerinit();
  617.  
  618.     if (ret) {
  619.         nnerror(101);
  620.         return(ret);
  621.     }
  622. /*
  623. *  initialize the template packets needed for transmission
  624. */
  625.     ret = protinit();
  626.  
  627.     return(ret);                /* set up empty packets */
  628. }
  629.  
  630. /*************************************************************************/
  631. /*  netshut
  632. *   Close all the connections and turn off the hardware.
  633. */
  634. netshut()
  635.     {
  636.     int i;
  637.  
  638.     for (i=0; i < NPORTS ; i++) 
  639.         if (portlist[i] != NULL)
  640.             netclose(i);
  641.  
  642.     netsleep(1);
  643.  
  644.     dlayershut();
  645.  
  646. }
  647.  
  648. /*************************************************************************/
  649. /* neteventinit
  650. *  load up the pointers for the event queue
  651. *  makes a circular list to follow, required for error messages
  652. */
  653. neteventinit()
  654.     {
  655.     int i;
  656.  
  657.     for (i=0; i < NEVENTS; i++)
  658.         nnq[i].next = i+1;
  659.  
  660.     nnq[NEVENTS-1].next = -1;
  661.  
  662.     nnefirst = 0;
  663.     nnelast = 0;
  664.     nnefree = 1;
  665. }
  666.