home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / misc / 9q920411 / socket.c < prev    next >
C/C++ Source or Header  |  1992-04-11  |  15KB  |  674 lines

  1. /* Application programming interface routines - based loosely on the
  2.  * "socket" model in Berkeley UNIX.
  3.  *
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include <stdio.h>
  7. #ifdef    __STDC__
  8. #include <stdarg.h>
  9. #endif
  10. #include "global.h"
  11. #include "mbuf.h"
  12. #include "netuser.h"
  13. #include "proc.h"
  14. #include "lzw.h"
  15. #include "usock.h"
  16. #include "socket.h"
  17.  
  18. char *Socktypes[] = {
  19.     "Not Used",
  20.     "TCP",
  21.     "UDP",
  22.     "AX25 I",
  23.     "AX25 UI",
  24.     "Raw IP",
  25.     "NETROM3",
  26.     "NETROM",
  27.     "Loc St",
  28.     "Loc Dg"
  29. };
  30. char Badsocket[] = "Bad socket";
  31. struct usock *Usock;        /* Socket entry array */
  32.  
  33. /* Initialize user socket array */
  34. void
  35. sockinit()
  36. {
  37.     if(Usock != NULLUSOCK)
  38.         return;    /* Already initialized */
  39.     Usock = (struct usock *)callocw(Nusock,sizeof(struct usock));
  40. }
  41.  
  42. /* Create a user socket, return socket index
  43.  * The mapping to actual protocols is as follows:
  44.  *        
  45.  *        
  46.  * ADDRESS FAMILY    Stream        Datagram    Raw        Seq. Packet
  47.  *
  48.  * AF_INET        TCP        UDP        IP
  49.  * AF_AX25        I-frames    UI-frames
  50.  * AF_NETROM                        NET/ROM L3  NET/ROM L4
  51.  * AF_LOCAL        stream loopback    packet loopback
  52.  */
  53. int
  54. socket(af,type,protocol)
  55. int af;        /* Address family */
  56. int type;    /* Stream or datagram */
  57. int protocol;    /* Used for raw IP sockets */
  58. {
  59.     register struct usock *up;
  60.     struct socklink *sp;
  61.     int s;
  62.  
  63.     for(up=Usock;up < &Usock[Nusock];up++)
  64.         if(up->type == NOTUSED)
  65.             break;
  66.  
  67.     if(up == &Usock[Nusock]){
  68.         /* None left */
  69.         errno = EMFILE;
  70.         return -1;
  71.     }
  72.     up->refcnt = 1;
  73.     s = up - Usock + SOCKBASE;
  74.     errno = 0;
  75.     up->noblock = 0;
  76.     up->rdysock = -1;
  77.     up->cb.p = NULLCHAR;
  78.     up->peername = up->name = NULLCHAR;
  79.     up->namelen = up->peernamelen = 0;
  80.     up->owner = Curproc;
  81.     up->obuf = NULLBUF;
  82.     up->tos = 0;
  83.     memset(up->errcodes,0,sizeof(up->errcodes));
  84.     memset(up->eol,0,sizeof(up->eol));
  85.     up->flush = '\n';    /* default is line buffered */
  86.     switch(af){
  87.     case AF_LOCAL:
  88.         switch(type){
  89.         case SOCK_STREAM:
  90.             up->type = TYPE_LOCAL_STREAM;
  91.             break;
  92.         case SOCK_DGRAM:
  93.             up->type = TYPE_LOCAL_DGRAM;
  94.             break;
  95.         default:
  96.             errno = ESOCKTNOSUPPORT;
  97.             break;
  98.         }
  99.         break;
  100.     case AF_AX25:
  101.         switch(type){
  102.         case SOCK_STREAM:
  103.             up->type = TYPE_AX25I;
  104.             break;
  105.         case SOCK_DGRAM:
  106.             up->type = TYPE_AX25UI;
  107.             break;
  108.         default:
  109.             errno = ESOCKTNOSUPPORT;
  110.             break;
  111.         }
  112.         break;
  113.     case AF_NETROM:
  114.         switch(type){
  115.         case SOCK_RAW:
  116.             up->type = TYPE_NETROML3;
  117.             break;
  118.         case SOCK_SEQPACKET:
  119.             up->type = TYPE_NETROML4;
  120.             break;
  121.         default:
  122.             errno = ESOCKTNOSUPPORT;
  123.             break;
  124.         }
  125.         break;
  126.     case AF_INET:
  127.         switch(type){
  128.         case SOCK_STREAM:
  129.             up->type = TYPE_TCP;
  130.             break;
  131.         case SOCK_DGRAM:
  132.             up->type = TYPE_UDP;
  133.             break;
  134.         case SOCK_RAW:
  135.             up->type = TYPE_RAW;
  136.             break;
  137.         default:
  138.             errno = ESOCKTNOSUPPORT;
  139.             break;
  140.         }
  141.         break;
  142.     default:
  143.         errno = EAFNOSUPPORT;
  144.         break;
  145.     }
  146.     /* Look for entry in protocol table */
  147.     for(sp = Socklink;sp->type != -1;sp++){
  148.         if(up->type == sp->type)
  149.             break;
  150.     }
  151.     up->sp = sp;
  152.     if(sp->type == -1 || sp->socket == NULLFP
  153.       ||(*sp->socket)(up,protocol) == -1){
  154.         errno = ESOCKTNOSUPPORT;
  155.         return -1;
  156.     }
  157.     return s;
  158. }
  159.  
  160. /* Attach a local address/port to a socket. If not issued before a connect
  161.  * or listen, will be issued automatically
  162.  */
  163. int
  164. bind(s,name,namelen)
  165. int s;        /* Socket index */
  166. char *name;    /* Local name */
  167. int namelen;    /* Length of name */
  168. {
  169.     register struct usock *up;
  170.     struct socklink *sp;
  171.  
  172.     if((up = itop(s)) == NULLUSOCK){
  173.         errno = EBADF;
  174.         return -1;
  175.     }
  176.     if(name == NULLCHAR){
  177.         errno = EFAULT;
  178.         return -1;
  179.     }
  180.     if(up->name != NULLCHAR){
  181.         /* Bind has already been issued */
  182.         errno = EINVAL;
  183.         return -1;
  184.     }
  185.     sp = up->sp;
  186.     if(sp->check != NULLFP && (*sp->check)(name,namelen) == -1){
  187.         /* Incorrect length or family for chosen protocol */
  188.         errno = EAFNOSUPPORT;
  189.         return -1;    
  190.     }
  191.     /* Stash name in an allocated block */
  192.     up->namelen = namelen;
  193.     up->name = mallocw(namelen);
  194.     memcpy(up->name,name,namelen);
  195.  
  196.     /* a bind routine is optional - don't fail if it isn't present */
  197.     if(sp->bind != NULLFP && (*sp->bind)(up) == -1){
  198.         errno = EOPNOTSUPP;
  199.         return -1;
  200.     }
  201.     return 0;
  202. }
  203. /* Post a listen on a socket */
  204. int
  205. listen(s,backlog)
  206. int s;        /* Socket index */
  207. int backlog;    /* 0 for a single connection, !=0 for multiple connections */
  208. {
  209.     register struct usock *up;
  210.     struct socklink *sp;
  211.  
  212.     if((up = itop(s)) == NULLUSOCK){
  213.         errno = EBADF;
  214.         return -1;
  215.     }
  216.     if(up->cb.p != NULLCHAR){
  217.         errno = EISCONN;
  218.         return -1;
  219.     }
  220.     sp = up->sp;
  221.     /* Fail if listen routine isn't present */
  222.     if(sp->listen == NULLFP || (*sp->listen)(up,backlog) == -1){
  223.         errno = EOPNOTSUPP;
  224.         return -1;
  225.     }
  226.     return 0;
  227. }
  228. /* Initiate active open. For datagram sockets, merely bind the remote address. */
  229. int
  230. connect(s,peername,peernamelen)
  231. int s;            /* Socket index */
  232. char *peername;        /* Peer name */
  233. int peernamelen;    /* Length of peer name */
  234. {
  235.     register struct usock *up;
  236.     struct socklink *sp;
  237.  
  238.     if((up = itop(s)) == NULLUSOCK){
  239.         errno = EBADF;
  240.         return -1;
  241.     }
  242.     if(peername == NULLCHAR){
  243.         /* Connect must specify a remote address */
  244.         errno = EFAULT;
  245.         return -1;
  246.     }
  247.     sp = up->sp;
  248.     /* Check name format, if checking routine is available */
  249.     if(sp->check != NULLFP && (*sp->check)(peername,peernamelen) == -1){
  250.         errno = EAFNOSUPPORT;
  251.         return -1;
  252.     }
  253.     if(up->peername != NULLCHAR)
  254.         free(up->peername);
  255.     up->peername = mallocw(peernamelen);
  256.     memcpy(up->peername,peername,peernamelen);
  257.     up->peernamelen = peernamelen;
  258.  
  259.     /* a connect routine is optional - don't fail if it isn't present */
  260.     if(sp->connect != NULLFP && (*sp->connect)(up) == -1){
  261.         return -1;
  262.     }
  263.     return 0;
  264. }
  265. /* Wait for a connection. Valid only for connection-oriented sockets. */
  266. int
  267. accept(s,peername,peernamelen)
  268. int s;            /* Socket index */
  269. char *peername;        /* Peer name */
  270. int *peernamelen;    /* Length of peer name */
  271. {
  272.     int i;
  273.     register struct usock *up;
  274.     struct socklink *sp;
  275.  
  276.     if((up = itop(s)) == NULLUSOCK){
  277.         errno = EBADF;
  278.         return -1;
  279.     }
  280.     if(up->cb.p == NULLCHAR){
  281.         errno = EOPNOTSUPP;
  282.         return -1;
  283.     }
  284.     sp = up->sp;
  285.     /* Fail if accept flag isn't set */
  286.     if(sp->accept == FALSE){
  287.         errno = EOPNOTSUPP;
  288.         return -1;
  289.     }
  290.     /* Wait for the state-change upcall routine to signal us */
  291.     while(up->cb.p != NULLCHAR && up->rdysock == -1){
  292.         if(up->noblock){
  293.             errno = EWOULDBLOCK;
  294.             return -1;
  295.         } else if((errno = pwait(up)) != 0){
  296.             return -1;
  297.         }
  298.     }
  299.     if(up->cb.p == NULLCHAR){
  300.         /* Blown away */
  301.         errno = EBADF;
  302.         return -1;
  303.     }
  304.     i = up->rdysock;
  305.     up->rdysock = -1;
  306.  
  307.     up = itop(i);
  308.     if(peername != NULLCHAR && peernamelen != NULL){
  309.         *peernamelen = min(up->peernamelen,*peernamelen);
  310.         memcpy(peername,up->peername,*peernamelen);
  311.     }
  312.     return i;
  313. }
  314. /* Low-level receive routine. Passes mbuf back to user; more efficient than
  315.  * higher-level functions recv() and recvfrom(). Datagram sockets ignore
  316.  * the len parameter.
  317.  */
  318. int
  319. recv_mbuf(s,bpp,flags,from,fromlen)
  320. int s;            /* Socket index */
  321. struct mbuf **bpp;    /* Place to stash receive buffer */
  322. int flags;        /* Unused; will control out-of-band data, etc */
  323. char *from;        /* Peer address (only for datagrams) */
  324. int *fromlen;        /* Length of peer address */
  325. {
  326.     register struct usock *up;
  327.     int cnt;
  328.     struct socklink *sp;
  329.  
  330.     if((up = itop(s)) == NULLUSOCK){
  331.         errno = EBADF;
  332.         return -1;
  333.     }
  334.     if(up->ibuf != NULLBUF){
  335.         /* Return input buffer */
  336.         cnt = len_p(up->ibuf);
  337.         if(bpp != NULLBUFP)
  338.             *bpp = up->ibuf;
  339.         else
  340.             free_p(up->ibuf);
  341.         up->ibuf = NULLBUF;        
  342.         return cnt;
  343.     }
  344.     sp = up->sp;
  345.     /* Fail if recv routine isn't present */
  346.     if(sp->recv == NULLFP || (cnt = (*sp->recv)(up,bpp,from,fromlen)) == -1){
  347.         errno = EOPNOTSUPP;
  348.         return -1;
  349.     }
  350.     return cnt;
  351. }
  352. /* Low level send routine; user supplies mbuf for transmission. More
  353.  * efficient than send() or sendto(), the higher level interfaces.
  354.  * The "to" and "tolen" parameters are ignored on connection-oriented
  355.  * sockets.
  356.  *
  357.  * In case of error, bp is freed so the caller doesn't have to worry about it.
  358.  */
  359. int
  360. send_mbuf(s,bp,flags,to,tolen)
  361. int s;            /* Socket index */
  362. struct mbuf *bp;    /* Buffer to send */
  363. int flags;        /* not currently used */
  364. char *to;        /* Destination, only for datagrams */
  365. int tolen;        /* Length of destination */
  366. {
  367.     register struct usock *up;
  368.     int cnt;
  369.     struct socklink *sp;
  370.  
  371.     if((up = itop(s)) == NULLUSOCK){
  372.         free_p(bp);
  373.         errno = EBADF;
  374.         return -1;
  375.     }
  376.     sp = up->sp;
  377.     /* Fail if send routine isn't present (shouldn't happen) */
  378.     if(sp->send == NULLFP){
  379.         free_p(bp);
  380.         return -1;
  381.     }
  382. #ifndef    notdef
  383.     if(up->obuf != NULLBUF){
  384.         /* If there's unflushed output, send it.
  385.          * Note the importance of clearing up->obuf
  386.          * before the recursive call!
  387.          */
  388.         struct mbuf *bp1;
  389.  
  390.         bp1 = up->obuf;
  391.         up->obuf = NULLBUF;
  392.         send_mbuf(s,bp1,flags,to,tolen);
  393.     }
  394. #endif
  395.     /* The proto send routine is expected to free the buffer
  396.      * we pass it even if the send fails
  397.      */
  398.     if((cnt = (*sp->send)(up,bp,to)) == -1){
  399.         errno = EOPNOTSUPP;
  400.         return -1;
  401.     }
  402.     return cnt;
  403. }
  404. /* Return local name passed in an earlier bind() call */
  405. int
  406. getsockname(s,name,namelen)
  407. int s;        /* Socket index */
  408. char *name;    /* Place to stash name */
  409. int *namelen;    /* Length of same */
  410. {
  411.     register struct usock *up;
  412.  
  413.     if((up = itop(s)) == NULLUSOCK){
  414.         errno = EBADF;
  415.         return -1;
  416.     }
  417.     if(name == NULLCHAR || namelen == (int *)NULL){
  418.         errno = EFAULT;
  419.         return -1;
  420.     }
  421.     if(up->name == NULLCHAR){
  422.         /* Not bound yet */
  423.         *namelen = 0;
  424.         return 0;
  425.     }
  426.     if(up->name != NULLCHAR){
  427.         *namelen = min(*namelen,up->namelen);
  428.         memcpy(name,up->name,*namelen);
  429.     }
  430.     return 0;
  431. }
  432. /* Get remote name, returning result of earlier connect() call. */
  433. int
  434. getpeername(s,peername,peernamelen)
  435. int s;            /* Socket index */
  436. char *peername;        /* Place to stash name */
  437. int *peernamelen;    /* Length of same */
  438. {
  439.     register struct usock *up;
  440.  
  441.     if((up = itop(s)) == NULLUSOCK){
  442.         errno = EBADF;
  443.         return -1;
  444.     }
  445.     if(up->peername == NULLCHAR){
  446.         errno = ENOTCONN;
  447.         return -1;
  448.     }
  449.     if(peername == NULLCHAR || peernamelen == (int *)NULL){
  450.         errno = EFAULT;
  451.         return -1;
  452.     }
  453.     *peernamelen = min(*peernamelen,up->peernamelen);
  454.     memcpy(peername,up->peername,*peernamelen);
  455.     return 0;
  456. }
  457. /* Return length of protocol queue, either send or receive. */
  458. int
  459. socklen(s,rtx)
  460. int s;        /* Socket index */
  461. int rtx;    /* 0 = receive queue, 1 = transmit queue */
  462. {
  463.     register struct usock *up;
  464.     struct socklink *sp;
  465.     int len = -1;
  466.  
  467.     if((up = itop(s)) == NULLUSOCK){
  468.         errno = EBADF;
  469.         return -1;
  470.     }
  471.     if(up->cb.p == NULLCHAR){
  472.         errno = ENOTCONN;
  473.         return -1;
  474.     }
  475.     if(rtx < 0 || rtx > 1){
  476.         errno = EINVAL;
  477.         return -1;
  478.     }
  479.     sp = up->sp;
  480.     /* Fail if qlen routine isn't present */
  481.     if(sp->qlen == NULLFP || (len = (*sp->qlen)(up,rtx)) == -1){
  482.         errno = EOPNOTSUPP;
  483.         return -1;
  484.     }
  485.     return len;
  486. }
  487. /* Force retransmission. Valid only for connection-oriented sockets. */
  488. int
  489. sockkick(s)
  490. int s;    /* Socket index */
  491. {
  492.     register struct usock *up;
  493.     struct socklink *sp;
  494.  
  495.     if((up = itop(s)) == NULLUSOCK){
  496.         errno = EBADF;
  497.         return -1;
  498.     }
  499.     sp = up->sp;
  500.     /* Fail if kick routine isn't present */
  501.     if(sp->kick == NULLFP){
  502.         errno = EOPNOTSUPP;
  503.         return -1;
  504.     }
  505.      if((*sp->kick)(up) == -1)
  506.         return -1;
  507.     return 0;
  508. }
  509.  
  510. /* Change owner of socket, return previous owner */
  511. struct proc *
  512. sockowner(s,newowner)
  513. int s;            /* Socket index */
  514. struct proc *newowner;    /* Process table address of new owner */
  515. {
  516.     register struct usock *up;
  517.     struct proc *pp;
  518.  
  519.     if((up = itop(s)) == NULLUSOCK){
  520.         errno = EBADF;
  521.         return NULLPROC;
  522.     }
  523.     pp = up->owner;
  524.     if(newowner != NULLPROC)
  525.         up->owner = newowner;
  526.     return pp;
  527. }
  528. /* Close down a socket three ways. Type 0 means "no more receives"; this
  529.  * replaces the incoming data upcall with a routine that discards further
  530.  * data. Type 1 means "no more sends", and obviously corresponds to sending
  531.  * a TCP FIN. Type 2 means "no more receives or sends". This I interpret
  532.  * as "abort the connection".
  533.  */
  534. int
  535. shutdown(s,how)
  536. int s;        /* Socket index */
  537. int how;    /* (see above) */
  538. {
  539.     register struct usock *up;
  540.     struct socklink *sp;
  541.  
  542.     if((up = itop(s)) == NULLUSOCK){
  543.         errno = EBADF;
  544.         return -1;
  545.     }
  546.     if(up->cb.p == NULLCHAR){
  547.         errno = ENOTCONN;
  548.         return -1;
  549.     }
  550.     sp = up->sp;
  551.     /* Just close the socket if special shutdown routine not present */
  552.     if(sp->shut == NULLFP){
  553.         close_s(s);
  554.     } else if((*sp->shut)(up,how) == -1){
  555.         return -1;
  556.     }
  557.     psignal(up,0);
  558.     return 0;
  559. }
  560. /* Close a socket, freeing it for reuse. Try to do a graceful close on a
  561.  * TCP socket, if possible
  562.  */
  563. int
  564. close_s(s)
  565. int s;        /* Socket index */
  566. {
  567.     register struct usock *up;
  568.     struct socklink *sp;
  569.  
  570.     if((up = itop(s)) == NULLUSOCK){
  571.         errno = EBADF;
  572.         return -1;
  573.     }
  574.     if(--up->refcnt > 0)
  575.         return 0;    /* Others are still using it */
  576.     usflush(s);
  577.     if(up->ibuf != NULLBUF){
  578.         free_p(up->ibuf);
  579.         up->ibuf = NULLBUF;
  580.     }
  581.     /* Call proto-specific close routine if there is one */
  582.     if((sp = up->sp) != NULL && sp->close != NULLFP)
  583.         (*sp->close)(up);
  584.  
  585.     if(up->zout != NULLLZW || up->zin != NULLLZW)
  586.         lzwfree(up);
  587.  
  588.     free(up->name);
  589.     free(up->peername);
  590.  
  591.     up->cb.p = NULLCHAR;
  592.     up->name = up->peername = NULLCHAR;
  593.     up->type = NOTUSED;
  594.     up->sp = NULL;
  595.     psignal(up,0);    /* Wake up anybody doing an accept() or recv() */
  596.     return 0;
  597. }
  598. /* Increment reference count for specified socket */
  599. int
  600. usesock(s)
  601. int s;
  602. {
  603.     struct usock *up;
  604.  
  605.     if((up = itop(s)) == NULLUSOCK){
  606.         errno = EBADF;
  607.         return -1;
  608.     }
  609.     up->refcnt++;
  610.     return 0;
  611. }
  612. /* Blow away all sockets belonging to a certain process. Used by killproc(). */
  613. void
  614. freesock(pp)
  615. struct proc *pp;
  616. {
  617.     register struct usock *up;
  618.     register int i;
  619.  
  620.     for(i=SOCKBASE;i < Nusock+SOCKBASE;i++){
  621.         up = itop(i);
  622.         if(up != NULLUSOCK && up->type != NOTUSED && up->owner == pp)
  623.             shutdown(i,2);
  624.     }
  625. }
  626. /* Set Internet type-of-service to be used */
  627. int
  628. settos(s,tos)
  629. int s,tos;
  630. {
  631.     struct usock *up;
  632.  
  633.     if((up = itop(s)) == NULLUSOCK){
  634.         errno = EBADF;
  635.         return -1;
  636.     }
  637.     up->tos = tos;
  638.     return 0;
  639. }
  640.  
  641. /* Return a pair of mutually connected sockets in sv[0] and sv[1] */
  642. int
  643. socketpair(af,type,protocol,sv)
  644. int af;
  645. int type;
  646. int protocol;
  647. int sv[];
  648. {
  649.     struct usock *up0, *up1;
  650.     if(sv == NULLINT){
  651.         errno = EFAULT;
  652.         return -1;
  653.     }
  654.     if(af != AF_LOCAL){
  655.         errno = EAFNOSUPPORT;
  656.         return -1;
  657.     }
  658.     if(type != SOCK_STREAM && type != SOCK_DGRAM){
  659.         errno = ESOCKTNOSUPPORT;
  660.         return -1;
  661.     }
  662.     if((sv[0] = socket(af,type,protocol)) == -1)
  663.         return -1;
  664.     if((sv[1] = socket(af,type,protocol)) == -1){
  665.         close_s(sv[0]);
  666.         return -1;
  667.     }
  668.     up0 = itop(sv[0]);
  669.     up1 = itop(sv[1]);
  670.     up0->cb.local->peer = up1;
  671.     up1->cb.local->peer = up0;
  672.     return sv[1];
  673. }
  674.