home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / NCSATELN / TEL23SRC.ZIP / ENGINE / USER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-05  |  15.8 KB  |  702 lines

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