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