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