home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / unixSyscall / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-27  |  28.7 KB  |  1,158 lines

  1. /* 
  2.  * socket.c --
  3.  *
  4.  *    Routines to emulate 4.3 BSD socket-related system calls for IPC
  5.  *    using the Internet protocol suite. The routines make calls to 
  6.  *    the Sprite Internet Server using Sprite system calls.
  7.  *
  8.  * Copyright 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /sprite/src/lib/c/unixSyscall/RCS/socket.c,v 1.16 92/03/27 12:26:24 shirriff Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <bit.h>
  18. #include <dev/net.h>
  19. #include <fs.h>
  20. #include <inet.h>
  21. #include <status.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <sys.h>
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <sys/uio.h>
  28. #include <netinet/in.h>
  29. #include <errno.h>
  30.  
  31. #include "compatInt.h"
  32.  
  33. static ReturnStatus Wait();
  34.  
  35. #ifdef DEBUG
  36. #  define    DebugMsg(status, string)     Stat_PrintMsg(status, string)
  37. #else
  38. #  define    DebugMsg(status, string)    ;
  39. #endif
  40.  
  41. static Boolean    gotHostName = FALSE;
  42. static char     myHostName[100];
  43. static char     streamDevice[100];
  44. static char     dgramDevice[100];
  45. static char     rawDevice[100];
  46.  
  47.  
  48. /*
  49.  *----------------------------------------------------------------------
  50.  *
  51.  * accept --
  52.  *
  53.  *    Accept a stream connection request. This call will create a new
  54.  *    connection to the Inet server upon notification that a remote
  55.  *    connection request is pending.
  56.  *
  57.  *    If the socket is non-blocking and no remote connection requests are
  58.  *    pending, EWOULDBLOCK is returned. If the socket is blockable,
  59.  *    this routine will wait until a remote connection request arrives.
  60.  *
  61.  * Results:
  62.  *    If > 0, the stream ID of the new connection.
  63.  *    If UNIX_ERROR, errno = 
  64.  *    EINVAL        - Bad size for *namePtr.
  65.  *    EWOULDBLOCK    - Non pending requests.
  66.  *
  67.  * Side effects:
  68.  *    A new stream is created.
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72.  
  73. int
  74. accept(socketID, addrPtr, addrLenPtr)
  75.     int            socketID;    /* Socket to listen on. */
  76.     struct sockaddr_in    *addrPtr;    /* Address of newly-accepted 
  77.                      * connection. (out) */
  78.     int            *addrLenPtr;    /* Size of *addrPtr. (in/out) */
  79. {
  80.     ReturnStatus    status;
  81.     int            newSocket;
  82.     ClientData        acceptToken;
  83.     int            addrLen;
  84.  
  85.     if (addrLenPtr == (int *) NULL) {
  86.     addrLen = 0;
  87.     addrPtr = (struct sockaddr_in *) NULL;
  88.     } else {
  89.     /*
  90.      * We deal with just Internet sockets.
  91.      */
  92.  
  93.     addrLen = *addrLenPtr;
  94.     if (addrLen < sizeof(struct sockaddr_in)) {
  95.         errno = EINVAL;
  96.         return(UNIX_ERROR);
  97.     }
  98.     }
  99.  
  100.  
  101.     /*
  102.      * Tell the Inet server to accept connections on the socket.  If a
  103.      * connection is made, a token is returned that is used to convert the
  104.      * connection into a new socket.  If no connections are currently
  105.      * available and the socket is non-blocking, FS_WOULD_BLOCK is
  106.      * returned. If the socket is blockable, the ioctl returns
  107.      * NET_NO_CONNECTS so and Wait() must be used to wait for a
  108.      * connection.
  109.      */
  110.  
  111.     status = Fs_IOControl(socketID, IOC_NET_ACCEPT_CONN_1, 
  112.             0, (Address) NULL, 
  113.             sizeof(acceptToken), (Address) &acceptToken);
  114.  
  115.     switch (status) {
  116.     case SUCCESS:
  117.         break;
  118.  
  119.     case FS_WOULD_BLOCK:
  120.         errno = EWOULDBLOCK;
  121.         return(UNIX_ERROR);
  122.         break;
  123.  
  124.         case NET_NO_CONNECTS:
  125.         /*
  126.          * Wait for the server to tell us that a request has arrived.
  127.          */
  128.         (void) Wait(socketID, TRUE, (Time *) NULL);
  129.  
  130.         /*
  131.          * There's a pending connection so retry the ioctl.
  132.          */
  133.         status = Fs_IOControl(socketID, IOC_NET_ACCEPT_CONN_1, 
  134.                 0, (Address) NULL, 
  135.                 sizeof(acceptToken), (Address) &acceptToken);
  136.         if (status != SUCCESS) {
  137.         DebugMsg(status, "accept (ioctl 1b)");
  138.         errno = Compat_MapCode(status);
  139.         return(UNIX_ERROR);
  140.         }
  141.         break;
  142.  
  143.     default:
  144.         DebugMsg(status, "accept (ioctl 1a)");
  145.         errno = Compat_MapCode(status);
  146.         return(UNIX_ERROR);
  147.         break;
  148.     } 
  149.  
  150.  
  151.     /*
  152.      * Create the new socket. This socket will be converted into the new
  153.      * connection.
  154.      */
  155.  
  156.     status = Fs_Open(streamDevice, FS_READ|FS_WRITE, 0666, &newSocket);
  157.     if (status != SUCCESS) {
  158.  
  159.     DebugMsg(status, "accept (open)");
  160.     errno = Compat_MapCode(status);
  161.     return(UNIX_ERROR);
  162.     }
  163.  
  164.     /*
  165.      * Make the new socket have the same characteristics as the
  166.      * connection socket. Also, find out who we are connected to.
  167.      */
  168.     status = Fs_IOControl(newSocket, IOC_NET_ACCEPT_CONN_2, 
  169.             sizeof(acceptToken), (Address) &acceptToken, 
  170.             addrLen, (Address) addrPtr);
  171.  
  172.     if (status != SUCCESS) {
  173.     DebugMsg(status, "accept (ioctl 2)");
  174.     errno = Compat_MapCode(status);
  175.     return(UNIX_ERROR);
  176.     }
  177.     if (addrLen > 0) {
  178.     addrPtr->sin_family = AF_INET;
  179.     }
  180.  
  181.     return(newSocket);
  182. }
  183.  
  184. /*
  185.  *----------------------------------------------------------------------
  186.  *
  187.  * bind --
  188.  *
  189.  *    Assigns a local <address,port> tuple to a socket that does 
  190.  *    not have one.
  191.  *
  192.  * Results:
  193.  *    If 0        - Successful.
  194.  *    If UNIX_ERROR, then errno = 
  195.  *    EINVAL        - Bad size for *namePtr, already bound to an address.
  196.  *    EADDRINUSE    - The address is already in use.
  197.  *    EADDRNOTAVAIL    - The address is not valid for this host.
  198.  *
  199.  * Side effects:
  200.  *    The socket local address is set.
  201.  *
  202.  *----------------------------------------------------------------------
  203.  */
  204.  
  205. int
  206. bind(socketID, namePtr, nameLen)
  207.     int            socketID;    /* Stream ID of unnamed socket. */
  208.     struct sockaddr    *namePtr;    /* Local address,port for this socket.*/
  209.     int            nameLen;    /* Size of *namePtr. */
  210. {
  211.     ReturnStatus    status;
  212.  
  213.     if (nameLen != sizeof(struct sockaddr_in)) {
  214.     errno = EINVAL;
  215.     return(UNIX_ERROR);
  216.     }
  217.  
  218.     status = Fs_IOControl(socketID, IOC_NET_SET_LOCAL_ADDR, 
  219.             nameLen, (Address) namePtr, 
  220.             0, (Address) NULL);
  221.  
  222.     if (status != SUCCESS) {
  223.     DebugMsg(status, "bind");
  224.     errno = Compat_MapCode(status);
  225.     return(UNIX_ERROR);
  226.     }
  227.     return(UNIX_SUCCESS);
  228. }
  229.  
  230. /*
  231.  *----------------------------------------------------------------------
  232.  *
  233.  * connect --
  234.  *
  235.  *    For a stream socket, create a connection to a remote host.
  236.  *    For a datagram socket, only receive datagrams from this remote 
  237.  *    address.
  238.  *
  239.  * Results:
  240.  *    If 0        - Successful.
  241.  *    If UNIX_ERROR, then errno = 
  242.  *    EINVAL        - Bad size for *namePtr,
  243.  *    EADDRINUSE    - The address is already in use.
  244.  *    EADDRNOTAVAIL    - The address is not valid for this host.
  245.  *    EISCONN        - The socket is already connected.
  246.  *    ETIMEDOUT    - The connection request timed-out.
  247.  *    ECONNREFUSED    - The remote host refused the connection.
  248.  *    ENETUNREACH    - The network isn't reachable from this host.
  249.  *    EWOULDBLOCK    - If non-blocking, the connection can't be completed
  250.  *                immediately.
  251.  *    EFAULT        - Invalid argument to the ioctl.
  252.  *
  253.  * Side effects:
  254.  *    A local address for the socket is given if it did not have one 
  255.  *    already.
  256.  *
  257.  *----------------------------------------------------------------------
  258.  */
  259.  
  260. int
  261. connect(socketID, namePtr, nameLen)
  262.     int            socketID;    /* Stream ID of socket. */
  263.     struct sockaddr    *namePtr;    /* Remote address,port to connect to.*/
  264.     int            nameLen;    /* Size of *namePtr. */
  265. {
  266.     ReturnStatus    status;
  267.     Time        oneMin;
  268.  
  269.     if (nameLen != sizeof(struct sockaddr_in)) {
  270.     errno = EINVAL;
  271.     return(UNIX_ERROR);
  272.     }
  273.  
  274.     status = Fs_IOControl(socketID, IOC_NET_CONNECT,
  275.             nameLen, (Address) namePtr, 
  276.             0, (Address) NULL);
  277.  
  278.     if (status == FS_WOULD_BLOCK) {
  279.     int flags = 0;
  280.     int statLen = sizeof(status);
  281.  
  282.     /*
  283.      * The connection didn't immeadiately complete, so wait if
  284.      * we're blocking or return EWOULDBLOCK if we're non-blocking.
  285.      */
  286.     status = Fs_IOControl(socketID, IOC_GET_FLAGS, 
  287.             0, (Address) NULL,
  288.             sizeof(flags), (Address) &flags);
  289.  
  290.     if (status != SUCCESS) {
  291.         DebugMsg(status, "connect (ioctl)");
  292.         panic("connect: GET_FLAGS failed.\n");
  293.     }
  294.  
  295.     if (flags & IOC_NON_BLOCKING) {
  296.         errno = EWOULDBLOCK;
  297.         return(UNIX_ERROR);
  298.     } 
  299.  
  300.     oneMin = time_OneMinute;
  301.     status = Wait(socketID, FALSE, &oneMin);
  302.  
  303.     if (status == FS_TIMEOUT) {
  304.         DebugMsg(status, "connect (select)");
  305.         errno = ETIMEDOUT;
  306.         return(UNIX_ERROR);
  307.     }
  308.  
  309.     /*
  310.      * See if the connection successfully completed. getsockopt converts
  311.      * the status to its Unix equivalent.
  312.      */
  313.     if (getsockopt(socketID, SOL_SOCKET, SO_ERROR, (char *) &status,
  314.         &statLen) < 0) {
  315.         return(UNIX_ERROR);
  316.     }
  317.     if (status != UNIX_SUCCESS) {
  318.         errno = status;
  319.         return(UNIX_ERROR);
  320.     }
  321.     return(UNIX_SUCCESS);
  322.  
  323.     } else if (status != SUCCESS) {
  324.     DebugMsg(status, "connect");
  325.     errno = Compat_MapCode(status);
  326.     return(UNIX_ERROR);
  327.     }
  328.     return(UNIX_SUCCESS);
  329. }
  330.  
  331. /*
  332.  *----------------------------------------------------------------------
  333.  *
  334.  * getpeername --
  335.  *
  336.  *    Find out the remote address that this socket is connected to.
  337.  *
  338.  * Results:
  339.  *    If 0        - Successful.
  340.  *    If UNIX_ERROR, then errno = 
  341.  *    EINVAL        - Bad size for *namePtr.
  342.  *    ENOTCONN    - The socket is not connected.
  343.  *    EFAULT        - Invalid argument to the ioctl.
  344.  *
  345.  * Side effects:
  346.  *    None.
  347.  *
  348.  *----------------------------------------------------------------------
  349.  */
  350.  
  351. int
  352. getpeername(socketID, namePtr, nameLenPtr)
  353.     int            socketID;    /* Stream ID of socket connected to 
  354.                      * remote peer. */
  355.     struct sockaddr    *namePtr;    /* Upon return, <addr,port> for 
  356.                          * remote peer. */
  357.     int            *nameLenPtr;    /* Size of *namePtr. (in/out) */
  358. {
  359.     ReturnStatus    status;
  360.  
  361.     /*
  362.      * Make sure the struct is at least as big as an internet address.
  363.      * It can be bigger because of unions with dec net structures.
  364.      */
  365.     if (nameLenPtr == (int *) NULL ||
  366.     *nameLenPtr < sizeof(struct sockaddr_in)) {
  367.     errno = EINVAL;
  368.     return(UNIX_ERROR);
  369.     }
  370.     *nameLenPtr = sizeof(struct sockaddr_in);
  371.  
  372.     status = Fs_IOControl(socketID, IOC_NET_GET_REMOTE_ADDR, 
  373.             0, (Address) NULL, 
  374.             *nameLenPtr, (Address) namePtr);
  375.  
  376.     if (status != SUCCESS) {
  377.     DebugMsg(status, "getpeername");
  378.     errno = Compat_MapCode(status);
  379.     return(UNIX_ERROR);
  380.     }
  381.     return(UNIX_SUCCESS);
  382. }
  383.  
  384. /*
  385.  *----------------------------------------------------------------------
  386.  *
  387.  * getsockname --
  388.  *
  389.  *    Find out the local address for this socket, which was
  390.  *    set with the bind routine or by the connect routine.
  391.  *
  392.  * Results:
  393.  *    If 0        - Successful.
  394.  *    If UNIX_ERROR, then errno = 
  395.  *    EINVAL        - Bad size for *namePtr.
  396.  *    EFAULT        - Invalid argument to the ioctl.
  397.  *
  398.  * Side effects:
  399.  *    None.
  400.  *
  401.  *----------------------------------------------------------------------
  402.  */
  403.  
  404. int
  405. getsockname(socketID, namePtr, nameLenPtr)
  406.     int            socketID;    /* Stream ID of socket to get name of.*/
  407.     struct sockaddr    *namePtr;    /* Upon return, current <addr,port> for
  408.                      * this socket. */
  409.     int            *nameLenPtr;    /* Size of *namePtr. (in/out) */
  410. {
  411.     ReturnStatus    status;
  412.  
  413.     if (nameLenPtr == (int *) NULL ||
  414.     *nameLenPtr != sizeof(struct sockaddr_in)) {
  415.     errno = EINVAL;
  416.     return(UNIX_ERROR);
  417.     }
  418.  
  419.     status = Fs_IOControl(socketID, IOC_NET_GET_LOCAL_ADDR, 
  420.             0, (Address) NULL, 
  421.             *nameLenPtr, (Address) namePtr);
  422.  
  423.     if (status != SUCCESS) {
  424.     DebugMsg(status, "getsockname");
  425.     errno = Compat_MapCode(status);
  426.     return(UNIX_ERROR);
  427.     }
  428.     return(UNIX_SUCCESS);
  429. }
  430.  
  431. /*
  432.  *----------------------------------------------------------------------
  433.  *
  434.  * getsockopt --
  435.  *
  436.  *    Get the value for a socket option.
  437.  *
  438.  * Results:
  439.  *    If 0        - Successful.
  440.  *    If UNIX_ERROR, then errno = 
  441.  *    EFAULT        - Invalid argument to the ioctl.
  442.  *
  443.  * Side effects:
  444.  *    None.
  445.  *
  446.  *----------------------------------------------------------------------
  447.  */
  448.  
  449. int
  450. getsockopt(socketID, level, optName, optVal, optLenPtr)
  451.     int        socketID;    /* Stream ID of socket to get options on. */
  452.     int        level;        /* Socket or protocol level to get the option.*/
  453.     int        optName;    /* Type of option to get. */
  454.     char    *optVal;    /* Address of buffer to store the result. */
  455.     int        *optLenPtr;    /* In: Size of *optVal, out: # of bytes stored
  456.                  * in *optVal. */
  457. {
  458.     ReturnStatus    status;
  459.     int            optionsArray[2];
  460.  
  461.     /*
  462.      * OptionsArray is used to give the server the values of "level"
  463.      * and "optName". A buffer ("newBufPtr") is needed to get the option
  464.      * value and the length of the value.
  465.      */
  466.     optionsArray[0] = level;
  467.     optionsArray[1] = optName;
  468.  
  469.     status = Fs_IOControl(socketID, IOC_NET_GET_OPTION,
  470.             sizeof(optionsArray), (Address) optionsArray, 
  471.             *optLenPtr, (Address) optVal);
  472.  
  473.     if (status != SUCCESS) {
  474.     DebugMsg(status, "getsockopt");
  475.     errno = Compat_MapCode(status);
  476.     return(UNIX_ERROR);
  477.     }
  478.  
  479.     if (optName == SO_ERROR) {
  480.     /*
  481.      * The error value is a Sprite ReturnStatus so we must convert it
  482.      * to the equivalent Unix value.
  483.      */
  484.  
  485.     *(int *)optVal = Compat_MapCode(*(int *)optVal);
  486.     }
  487.  
  488.     return(UNIX_SUCCESS);
  489. }
  490.  
  491. /*
  492.  *----------------------------------------------------------------------
  493.  *
  494.  * setsockopt --
  495.  *
  496.  *    Set the value for a socket option.
  497.  *
  498.  * Results:
  499.  *    If 0        - Successful.
  500.  *    If UNIX_ERROR, then errno = 
  501.  *    EFAULT        - Invalid argument to the ioctl.
  502.  *
  503.  * Side effects:
  504.  *    None.
  505.  *
  506.  *----------------------------------------------------------------------
  507.  */
  508.  
  509. /*VARARGS  (makes lint happy) */
  510. int
  511. setsockopt(socketID, level, optName, optVal, optLen)
  512.     int        socketID;    /* Stream ID of socket to set options on. */
  513.     int        level;        /* Socket or protocol level to get the option.*/
  514.     int        optName;    /* Type of option to get. */
  515.     char    *optVal;    /* Address of buffer to store the result. */
  516.     int        optLen;        /* Size of *optVal. */
  517. {
  518.     ReturnStatus    status;
  519.     int            *newBufPtr;
  520.  
  521.     /*
  522.      * To pass the level, the type of option and the option value to the
  523.      * server, we allocate a new buffer and put the level and type in the
  524.      * first 2 slots and then copy the value to the rest of the buffer.
  525.      */
  526.     newBufPtr = (int *) malloc((unsigned) (2 * sizeof(int) + optLen));
  527.     newBufPtr[0] = level;
  528.     newBufPtr[1] = optName;
  529.     bcopy(optVal, (char *) &newBufPtr[2], optLen);
  530.  
  531.     status = Fs_IOControl(socketID, IOC_NET_SET_OPTION,
  532.             2 * sizeof(int) + optLen, (Address) newBufPtr,
  533.             0, (Address) NULL);
  534.  
  535.     free((char *) newBufPtr);
  536.  
  537.     if (status != SUCCESS) {
  538.     DebugMsg(status, "getsockopt");
  539.     errno = Compat_MapCode(status);
  540.     return(UNIX_ERROR);
  541.     }
  542.     return(UNIX_SUCCESS);
  543. }
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  * listen --
  549.  *
  550.  *    Allows a stream socket to accept remote connection requests and to
  551.  *    specify how many such requests will be queued up before they 
  552.  *    are refused.
  553.  *
  554.  * Results:
  555.  *    If 0        - Successful.
  556.  *    If UNIX_ERROR, then errno = 
  557.  *    EOPNOTSUPP    - The socket type doesn't allow a listen operation.
  558.  *    EFAULT        - Invalid argument to the ioctl.
  559.  *
  560.  * Side effects:
  561.  *    None.
  562.  *
  563.  *----------------------------------------------------------------------
  564.  */
  565.  
  566. int
  567. listen(socketID, backlog)
  568.     int    socketID;    /* Stream ID of socket to be put in listen mode. */
  569.     int    backlog;    /* How many connection requests to queue. */
  570. {
  571.     ReturnStatus    status;
  572.  
  573.     status = Fs_IOControl(socketID, IOC_NET_LISTEN,
  574.             sizeof(backlog), (Address) &backlog, 
  575.             0, (Address) NULL);
  576.  
  577.     if (status != SUCCESS) {
  578.     DebugMsg(status, "listen");
  579.     errno = Compat_MapCode(status);
  580.     return(UNIX_ERROR);
  581.     }
  582.     return(UNIX_SUCCESS);
  583. }
  584.  
  585. /*
  586.  *----------------------------------------------------------------------
  587.  *
  588.  * recv --
  589.  *
  590.  *    Read data from a connected socket. 
  591.  *
  592.  * Results:
  593.  *    See recvfrom().
  594.  *
  595.  * Side effects:
  596.  *    None.
  597.  *
  598.  *----------------------------------------------------------------------
  599.  */
  600.  
  601. int
  602. recv(socketID, bufPtr, bufSize, flags)
  603.     int        socketID;
  604.     char    *bufPtr;    /* Address of buffer to place the data in. */
  605.     int        bufSize;    /* Size of *bufPtr. */
  606.     int        flags;        /* Type of operatrion: OR of MSG_OOB, MSG_PEEK*/
  607. {
  608.     return(recvfrom(socketID, bufPtr, bufSize, flags, 
  609.         (struct sockaddr *) NULL, (int *) NULL));
  610. }
  611.  
  612. /*
  613.  *----------------------------------------------------------------------
  614.  *
  615.  * recvfrom --
  616.  *
  617.  *    Read data from a socket.
  618.  *
  619.  * Results:
  620.  *    If 0        - Successful.
  621.  *    If UNIX_ERROR, then errno = 
  622.  *    EINVAL        - Bad size or address for senderPtr, senderLenPtr.
  623.  *    EWOULDBLOCK    - If non-blocking, no data are available.
  624.  *    EFAULT        - Invalid argument to the ioctl.
  625.  *
  626.  * Side effects:
  627.  *    None.
  628.  *
  629.  *----------------------------------------------------------------------
  630.  */
  631.  
  632. int
  633. recvfrom(socketID, bufPtr, bufSize, flags, senderPtr, senderLenPtr)
  634.     int            socketID;    /* Socket to read. */
  635.     char        *bufPtr;    /* Buffer to place the data in. */
  636.     int            bufSize;    /* Size of *bufPtr. */
  637.     int            flags;        /* Type of operatrion: OR of 
  638.                      *  MSG_OOB, MSG_PEEK*/
  639.     struct sockaddr    *senderPtr;    /* Address of sender of the data. */
  640.     int            *senderLenPtr;    /* Size of *senderPtr. (in/out) */
  641. {
  642.     ReturnStatus    status;
  643.     int            amountRead;
  644.  
  645.     if (senderPtr != (struct sockaddr *) NULL) {
  646.     if ((senderLenPtr == (int *) NULL) ||
  647.         (*senderLenPtr != sizeof(struct sockaddr_in))) {
  648.         errno = EINVAL;
  649.         return(UNIX_ERROR);
  650.     }
  651.     }
  652.  
  653.     /*
  654.      * If there are flags, ship them to the server.
  655.      */
  656.     if (flags != 0) {
  657.     status = Fs_IOControl(socketID, IOC_NET_RECV_FLAGS,
  658.                 sizeof(flags), (Address) &flags, 
  659.                 0, (Address) NULL);
  660.     if (status != SUCCESS) {
  661.         DebugMsg(status, "recvfrom (ioctl recv_flags)");
  662.         errno = Compat_MapCode(status);
  663.         return(UNIX_ERROR);
  664.     }
  665.     }
  666.  
  667.     status = Fs_Read(socketID, bufSize, bufPtr, &amountRead);
  668.     if (status != SUCCESS) {
  669.     DebugMsg(status, "recvfrom (read)");
  670.     errno = Compat_MapCode(status);
  671.     return(UNIX_ERROR);
  672.     }
  673.  
  674.     /*
  675.      * If the caller wants the address of the sender, ask the server for it.
  676.      */
  677.     if (senderPtr != (struct sockaddr *) NULL) {
  678.     status = Fs_IOControl(socketID, IOC_NET_RECV_FROM,
  679.                 0, (Address) NULL,
  680.                 *senderLenPtr, (Address) senderPtr);
  681.     if (status != SUCCESS) {
  682.         DebugMsg(status, "recvfrom (ioctl get_remote)");
  683.         errno = Compat_MapCode(status);
  684.         return(UNIX_ERROR);
  685.     }
  686.     }
  687.     return(amountRead);
  688. }
  689.  
  690. /*
  691.  *----------------------------------------------------------------------
  692.  *
  693.  * recvmsg --
  694.  *
  695.  *    Read data from a socket using multiple buffers.
  696.  *
  697.  * Results:
  698.  *    If 0        - Successful.
  699.  *    If UNIX_ERROR, then errno = 
  700.  *    EINVAL        - Bad size or address for msg_name, msg_namelen;
  701.  *                I/O vector length too big.
  702.  *    EWOULDBLOCK    - If non-blocking, no data are available.
  703.  *    EFAULT        - Invalid argument to the ioctl, null address 
  704.  *               for msgPtr.
  705.  *
  706.  * Side effects:
  707.  *    None.
  708.  *
  709.  *----------------------------------------------------------------------
  710.  */
  711.  
  712. int
  713. recvmsg(socketID, msgPtr, flags)
  714.     int            socketID;    /* Sokect to read data from. */
  715.     struct msghdr    *msgPtr;    /* I/O vector of buffers to store the
  716.                      * data. */
  717.     int            flags;        /* Type of operatrion: OR of 
  718.                      *  MSG_OOB, MSG_PEEK*/
  719. {
  720.     ReturnStatus    status;
  721.     int            amountRead;
  722.  
  723.  
  724.     if (msgPtr == (struct msghdr *) NULL) {
  725.     errno = EFAULT;
  726.     return(UNIX_ERROR);
  727.     }
  728.  
  729.     if (msgPtr->msg_name != (Address) NULL) {
  730.     if (msgPtr->msg_namelen != sizeof(struct sockaddr_in)) {
  731.         errno = EINVAL;
  732.         return(UNIX_ERROR);
  733.     }
  734.     }
  735.  
  736.     if (msgPtr->msg_iovlen > MSG_MAXIOVLEN) {
  737.     errno = EINVAL;
  738.     return(UNIX_ERROR);
  739.     }
  740.  
  741.     /*
  742.      * If there are flags, ship them to the server.
  743.      */
  744.     if (flags != 0) {
  745.     status = Fs_IOControl(socketID, IOC_NET_RECV_FLAGS,
  746.                 sizeof(flags), (Address) &flags, 
  747.                 0, (Address) NULL);
  748.     if (status != SUCCESS) {
  749.         DebugMsg(status, "recvmsg (ioctl recv_flags)");
  750.         errno = Compat_MapCode(status);
  751.         return(UNIX_ERROR);
  752.     }
  753.     }
  754.  
  755.     amountRead = readv(socketID, msgPtr->msg_iov, msgPtr->msg_iovlen);
  756.     if (amountRead < 0) {
  757.     DebugMsg(errno, "recvmsg (readv)");
  758.     }
  759.     
  760.     /*
  761.      * If the caller wants the address of the sender, ask the server for it.
  762.      */
  763.     if (msgPtr->msg_name != (Address) NULL) {
  764.     status = Fs_IOControl(socketID, IOC_NET_RECV_FROM,
  765.             0, (Address) NULL,
  766.             msgPtr->msg_namelen, (Address) msgPtr->msg_name);
  767.     if (status != SUCCESS) {
  768.         DebugMsg(status, "recvmsg (ioctl recv_from)");
  769.         errno = Compat_MapCode(status);
  770.         return(UNIX_ERROR);
  771.     }
  772.     }
  773.  
  774.     return(amountRead);
  775. }
  776.  
  777. /*
  778.  *----------------------------------------------------------------------
  779.  *
  780.  * send --
  781.  *
  782.  *    Write data to a connected socket.
  783.  *
  784.  * Results:
  785.  *    See sendto().
  786.  *
  787.  * Side effects:
  788.  *    None.
  789.  *
  790.  *----------------------------------------------------------------------
  791.  */
  792.  
  793. int
  794. send(socketID, bufPtr, bufSize, flags)
  795.     int        socketID;    /* Socket to send data on. */
  796.     char    *bufPtr;    /* Address of buffer to send. */
  797.     int        bufSize;    /* Size of *bufPtr. */
  798.     int        flags;        /* Type of operatrion: OR of 
  799.                  *  MSG_OOB, MSG_PEEK, MSG_DONTROUTE. */
  800. {
  801.     return(sendto(socketID, bufPtr, bufSize, flags,(struct sockaddr *)NULL, 0));
  802. }
  803.  
  804. /*
  805.  *----------------------------------------------------------------------
  806.  *
  807.  * sendto --
  808.  *
  809.  *    Send a message from a socket.
  810.  *
  811.  * Results:
  812.  *    If 0        - Successful.
  813.  *    If UNIX_ERROR, then errno = 
  814.  *    EINVAL        - Bad size or address for destPtr, destLen..
  815.  *    EWOULDBLOCK    - If non-blocking, the server buffers are too
  816.  *              full to accept the data.
  817.  *    EMSGSIZE    - The buffer is too large to be sent in 1 packet.
  818.  *    EFAULT        - Invalid argument to the ioctl.
  819.  *
  820.  * Side effects:
  821.  *    None.
  822.  *
  823.  *----------------------------------------------------------------------
  824.  */
  825.  
  826. int
  827. sendto(socketID, bufPtr, bufSize, flags, destPtr, destLen)
  828.     int        socketID;    /* Socket to send data on. */
  829.     char    *bufPtr;    /* Address of buffer to send. */
  830.     int        bufSize;    /* Size of *bufPtr. */
  831.     int        flags;        /* Type of operatrion: OR of 
  832.                  *  MSG_OOB, MSG_PEEK, MSG_DONTROUTE. */
  833.     struct sockaddr    *destPtr;    /* Destination to send the data to. */
  834.     int            destLen;    /* Size of *destPtr.  */
  835. {
  836.     ReturnStatus    status;
  837.     int            numWritten;
  838.  
  839.     /*
  840.      * If either the flags or a destination are given, send them to the server.
  841.      */
  842.     if ((flags != 0) || (destPtr != (struct sockaddr *) NULL)) {
  843.     Net_SendInfo    sendInfo;
  844.  
  845.     if (destPtr != (struct sockaddr *) NULL) {
  846.         if (destLen != sizeof(struct sockaddr_in)) {
  847.         errno = EINVAL;
  848.         return(UNIX_ERROR);
  849.         }
  850.         sendInfo.addressValid = TRUE;
  851.         sendInfo.address.inet = *(Net_InetSocketAddr *) destPtr;
  852.     } else {
  853.         sendInfo.addressValid = FALSE;
  854.     }
  855.     sendInfo.flags = flags;
  856.  
  857.     status = Fs_IOControl(socketID, IOC_NET_SEND_INFO,
  858.             sizeof(sendInfo), (Address) &sendInfo, 
  859.             0, (Address) NULL);
  860.     if (status != SUCCESS) {
  861.         DebugMsg(status, "sendto (ioctl)");
  862.         errno = Compat_MapCode(status);
  863.         return(UNIX_ERROR);
  864.     }
  865.     }
  866.  
  867.     status = Fs_Write(socketID, bufSize, bufPtr, &numWritten);
  868.     if (status != SUCCESS) {
  869.     DebugMsg(status, "sendto (write)");
  870.     errno = Compat_MapCode(status);
  871.     return(UNIX_ERROR);
  872.     }
  873.     return(numWritten);
  874. }
  875.  
  876. /*
  877.  *----------------------------------------------------------------------
  878.  *
  879.  * sendmsg --
  880.  *
  881.  *    Send a message from a socket.
  882.  *
  883.  * Results:
  884.  *    If 0        - Successful.
  885.  *    If UNIX_ERROR, then errno = 
  886.  *    EINVAL        - Bad size or address for msg_name, msg_namelen;
  887.  *                I/O vector length too big.
  888.  *    EWOULDBLOCK    - If non-blocking, the server buffers are too full 
  889.  *              accept the data.
  890.  *    EFAULT        - Invalid argument to the ioctl, null address 
  891.  *               for msgPtr.
  892.  *
  893.  * Side effects:
  894.  *    None.
  895.  *
  896.  *----------------------------------------------------------------------
  897.  */
  898.  
  899. int
  900. sendmsg(socketID, msgPtr, flags)
  901.     int            socketID;    /* Socket to send data on. */
  902.     struct msghdr    *msgPtr;    /* I/O vector of buffers containing
  903.                      * data to send. */
  904.     int            flags;        /* Type of operatrion: OR of 
  905.                      *  MSG_OOB, MSG_PEEK, MSG_DONTROUTE. */
  906. {
  907.     ReturnStatus    status;
  908.     int            numWritten;
  909.  
  910.     if (msgPtr == (struct msghdr *) NULL) {
  911.     errno = EFAULT;
  912.     return(UNIX_ERROR);
  913.     }
  914.  
  915.     if (msgPtr->msg_iovlen > MSG_MAXIOVLEN) {
  916.     errno = EINVAL;
  917.     return(UNIX_ERROR);
  918.     }
  919.     
  920.     if ((flags != 0) || (msgPtr->msg_name != (Address) NULL)) {
  921.     Net_SendInfo    sendInfo;
  922.  
  923.     if (msgPtr->msg_name != (Address) NULL) {
  924.         if (msgPtr->msg_namelen != sizeof(struct sockaddr_in)) {
  925.         errno = EINVAL;
  926.         return(UNIX_ERROR);
  927.         }
  928.         sendInfo.addressValid = TRUE;
  929.         sendInfo.address.inet = *(Net_InetSocketAddr *)msgPtr->msg_name;
  930.     } else {
  931.         sendInfo.addressValid = FALSE;
  932.     }
  933.     sendInfo.flags = flags;
  934.  
  935.     status = Fs_IOControl(socketID, IOC_NET_SEND_INFO,
  936.                 sizeof(sendInfo), (Address) &sendInfo, 
  937.                 0, (Address) NULL);
  938.  
  939.     if (status != SUCCESS) {
  940.         DebugMsg(status, "sendmsg (ioctl)");
  941.         errno = Compat_MapCode(status);
  942.         return(UNIX_ERROR);
  943.     }
  944.     }
  945.  
  946.     numWritten = writev(socketID, msgPtr->msg_iov, msgPtr->msg_iovlen);
  947.     if (numWritten < 0) {
  948.     DebugMsg(errno, "sendmsg (writev)");
  949.     }
  950.     return(numWritten);
  951. }
  952.  
  953. /*
  954.  *----------------------------------------------------------------------
  955.  *
  956.  * socket --
  957.  *
  958.  *    Create a socket in the Internet domain.
  959.  *
  960.  * Results:
  961.  *    If > 0, the stream ID of the new socket.
  962.  *    If UNIX_ERROR, then errno = 
  963.  *    EINVAL        - "domain" did not specify the Internet domain.
  964.  *    ?        - Error from Fs_Open, Fs_IOControl.
  965.  *
  966.  * Side effects:
  967.  *    A new stream is created.
  968.  *
  969.  *----------------------------------------------------------------------
  970.  */
  971.  
  972. int
  973. socket(domain, type, protocol)
  974.     int    domain;        /* Type of communications domain */
  975.     int    type;        /* Type of socket: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW. */
  976.     int    protocol;    /* Specific protocol to use. */
  977. {
  978.     ReturnStatus    status;
  979.     int            streamID;
  980.  
  981.     if (domain != PF_INET) {
  982.     errno = EINVAL;
  983.     return(UNIX_ERROR);
  984.     }
  985.  
  986.     if (!gotHostName) {
  987.     gotHostName = TRUE;
  988.     if (gethostname(myHostName, sizeof(myHostName)) != 0) {
  989.         panic("socket: Can't find my hostname\n");
  990.     }
  991.     sprintf(streamDevice, INET_STREAM_NAME_FORMAT, myHostName);
  992.     sprintf(dgramDevice, INET_DGRAM_NAME_FORMAT, myHostName);
  993.     sprintf(rawDevice, INET_RAW_NAME_FORMAT, myHostName);
  994.     }
  995.  
  996.     do {
  997.     if (type == SOCK_STREAM) {
  998.         status = Fs_Open(streamDevice, FS_READ|FS_WRITE, 0666, &streamID);
  999.         if (status != SUCCESS) {
  1000.         DebugMsg(status, "socket (stream)");
  1001.         errno = Compat_MapCode(status);
  1002.         if (errno != EINTR) {
  1003.             return(UNIX_ERROR);
  1004.         }
  1005.         }
  1006.     } else if (type == SOCK_DGRAM) {
  1007.         status = Fs_Open(dgramDevice, FS_READ|FS_WRITE, 0666, &streamID);
  1008.         if (status != SUCCESS) {
  1009.         DebugMsg(status, "socket (datagram)");
  1010.         errno = Compat_MapCode(status);
  1011.         if (errno != EINTR) {
  1012.             return(UNIX_ERROR);
  1013.         }
  1014.         }
  1015.     } else if (type == SOCK_RAW) {
  1016.         status = Fs_Open(rawDevice, FS_READ|FS_WRITE, 0666, &streamID);
  1017.         if (status != SUCCESS) {
  1018.         DebugMsg(status, "socket (raw)");
  1019.         errno = Compat_MapCode(status);
  1020.         if (errno != EINTR) {
  1021.             return(UNIX_ERROR);
  1022.         }
  1023.         }
  1024.     } else {
  1025.         errno = EINVAL;
  1026.         return(UNIX_ERROR);
  1027.     }
  1028.     } while (status != SUCCESS);
  1029.  
  1030.     if (protocol != 0) {
  1031.     do {
  1032.         status = Fs_IOControl(streamID, IOC_NET_SET_PROTOCOL,
  1033.                 sizeof(protocol), (Address) &protocol, 
  1034.                 0, (Address) NULL);
  1035.         if (status != SUCCESS) {
  1036.         DebugMsg(status, "socket (ioctl)");
  1037.         errno = Compat_MapCode(status);
  1038.         if (errno != EINTR) {
  1039.             return(UNIX_ERROR);
  1040.         }
  1041.         }
  1042.     } while (status != SUCCESS);
  1043.     }
  1044.  
  1045.     return(streamID);
  1046. }
  1047.  
  1048. /*
  1049.  *----------------------------------------------------------------------
  1050.  *
  1051.  * shutdown --
  1052.  *
  1053.  *    Shut down part of a full-duplex connection.
  1054.  *
  1055.  * Results:
  1056.  *    0        - The action was successful.
  1057.  *
  1058.  * Side effects:
  1059.  *    None.
  1060.  *
  1061.  *----------------------------------------------------------------------
  1062.  */
  1063.  
  1064. int
  1065. shutdown(socketID, action)
  1066.     int        socketID;    /* Socket to shut down. */
  1067.     int        action;        /* 0 -> disallow further recvs, 
  1068.                  * 1 -> disallow further sends,
  1069.                  * 2 -> combination of above. */
  1070. {
  1071.     ReturnStatus    status;
  1072.  
  1073.     status = Fs_IOControl(socketID, IOC_NET_SHUTDOWN, 
  1074.             sizeof(action), (Address) &action, 
  1075.             0, (Address) NULL);
  1076.  
  1077.     if (status != SUCCESS) {
  1078.     DebugMsg(status, "shutdown");
  1079.     errno = Compat_MapCode(status);
  1080.     return(UNIX_ERROR);
  1081.     }
  1082.     return(UNIX_SUCCESS);
  1083. }
  1084.  
  1085.  
  1086. /*
  1087.  *----------------------------------------------------------------------
  1088.  *
  1089.  * Wait --
  1090.  *
  1091.  *    Wait for the Inet server to indicate that a socket is ready
  1092.  *    for some action.
  1093.  *
  1094.  * Results:
  1095.  *    SUCCESS, or FS_TIMEOUT if a timeout occurred.
  1096.  *
  1097.  * Side effects:
  1098.  *    None.
  1099.  *
  1100.  *----------------------------------------------------------------------
  1101.  */
  1102.  
  1103. static ReturnStatus
  1104. Wait(socketID, readSelect, timeOutPtr)
  1105.     int     socketID;    /* Socket to wait on. */
  1106.     Boolean    readSelect;    /* If TRUE, select for reading, else select for
  1107.                  *  writing. */
  1108.     Time    *timeOutPtr;    /* Timeout to use for select. */
  1109. {
  1110.     ReturnStatus    status;
  1111.     int            numReady;
  1112.  
  1113.     /*
  1114.      * Wait until the Inet server indicates the socket is ready.
  1115.      */
  1116.  
  1117.     if (socketID < 32) {
  1118.     int    mask;
  1119.  
  1120.     mask = 1 << socketID;
  1121.     if (readSelect) {
  1122.         status = Fs_Select(socketID + 1, timeOutPtr, &mask, 
  1123.                     (int *) NULL, (int *) NULL, &numReady);
  1124.     } else {
  1125.         status = Fs_Select(socketID + 1, timeOutPtr, (int *) NULL, 
  1126.                     &mask, (int *) NULL, &numReady);
  1127.     }
  1128.     } else {
  1129.     int    *maskPtr;
  1130.  
  1131.     Bit_Alloc(socketID + 1, maskPtr);
  1132.     Bit_Set(socketID, maskPtr);
  1133.  
  1134.     if (readSelect) {
  1135.         status = Fs_Select(socketID + 1, timeOutPtr, maskPtr, 
  1136.                     (int *) NULL, (int *) NULL, &numReady);
  1137.     } else {
  1138.         status = Fs_Select(socketID + 1, timeOutPtr, (int *) NULL,
  1139.                     maskPtr, (int *) NULL, &numReady);
  1140.     }
  1141.     free((char *) maskPtr);
  1142.     }
  1143.  
  1144.     if (status == FS_TIMEOUT) {
  1145.     return(status);
  1146.     } else if (status != SUCCESS) {
  1147.     Stat_PrintMsg(status, "Wait (socket.c)");
  1148.     panic("Wait (socket.c): Fs_Select failed.\n");
  1149.     }
  1150.  
  1151.     if (numReady != 1) {
  1152.     panic("Wait (socket.c): Fs_Select returned %d ready\n",
  1153.                 numReady);
  1154.     }
  1155.  
  1156.     return(SUCCESS);
  1157. }
  1158.