net.c


Index

  • AddrToHost (returns static char *)
  • NetSetErrno (returns static void )
  • strerror (returns const char *)
  • NetErrStr (returns const char *)
  • NetErrNo (returns NetErrnoType )
  • NetMakeWelcome (returns SOCKET )
  • NetNewConnection (returns int )
  • NetCloseConnection (returns void )
  • NetClientDataAvail (returns int )
  • NetGetClientHostname (returns char * )
  • AddrToHost (returns static char * )
  • NetSetErrno (returns static void )

  • #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <sys/ioctl.h>
    #include <errno.h>
    #include <string.h>
    #include "net.h"
    
    static char *AddrToHost(struct in_addr *addr, char *hname, int maxhostlen);
    static void NetSetErrno(NetErrnoType e);
    
    static NetErrnoType net_errno = E_NET_OK;
    static int saved_errno = 0;
    
    /* Translations between ``net_errno'' values and human readable strings.
    */
    static const char *net_syserrlist[] = {
            "All was chill"
    };
    
    
    
    #ifdef STRERROR_NOT_DEFINED
    const char *strerror(int errno) { return sys_errlist[errno]; }
    #endif
    
    
    
    /* NetErrStr()
     *--------------------------------------------------------------------
     * Returns a diagnostic message for the last failure.
     */
    const char *NetErrStr()
    {
      return (net_errno==E_NET_ERRNO) ? strerror(saved_errno) :
        net_syserrlist[net_errno];
    }
    
    /* NetErrNo()
     *--------------------------------------------------------------------
     * Returns a diagnostic number for the last failure.
     */
    NetErrnoType NetErrNo()
    {
      return net_errno;
    }
    
    
    
    /* NetMakeWelcome()
     *--------------------------------------------------------------------
     * Creates a socket that listens for incoming connections.
     *--------------------------------------------------------------------
     * Creates a socket on the local machine at on given ``port''.
     * Call @NewConnection() and pass the socket returned by this function to
     * it.
     *
     * Returns a socket on success or -1 on error.
     */
    SOCKET
    NetMakeWelcome(int port)
    {
      int fd;
      struct sockaddr_in addr;
      int v;
    
      fd = socket(AF_INET, SOCK_STREAM, 0);
      if(fd == -1)
        {
          NetSetErrno(E_NET_ERRNO);
          return -1;
        }
    
      v = 1;
      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
    
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = INADDR_ANY;
      if(bind(fd, &addr, sizeof(addr)))
        {
          NetSetErrno(E_NET_ERRNO);
          return -1;
        }
      if(listen(fd, 5))
        {
          NetSetErrno(E_NET_ERRNO);
          return -1;
        }
    
      NetSetErrno(E_NET_OK);
      return fd;
    }
    
    
    
    /* NetNewConnection()
     *--------------------------------------------------------------------
     * Waits for a new connection.
     *--------------------------------------------------------------------
     * Waits for a new connection on the welcome socket. Once a connection
     * is attempted from a remote host, initializes the client ``newc''
     * and creates a new socket for it to create.
     *
     * Returns -1 on error and 0 on success.
     */
    int
    NetNewConnection(w, newc)
         SOCKET w;
         ClientPtr newc;
    {
      int newfd;
      struct sockaddr_in addr;
      int addrlen = sizeof(addr);
    
      do
          {
              errno = 0;
              if(((newfd = accept(w, &addr, &addrlen)) == -1)
                 && errno != EINTR)
                  {
                    NetSetErrno(E_NET_ERRNO);
                    return -1;
                  }
          } while(errno == EINTR);
    
      ResetClient(newc);
      InitClient(newc);
      SetClientFd(newc, newfd);
    
      if(GetClientMaxHlen(newc))
          AddrToHost(&addr.sin_addr,
                     GetClientHname(newc), GetClientMaxHlen(newc));
    
      NetSetErrno(E_NET_OK);
      return 0;
    }
    
    
    /* NetCloseConnection()
     *--------------------------------------------------------------------
     * Closes a client's connection.
     */
    void
    NetCloseConnection(c)
         ClientPtr c;
    {
        close(GetClientFd(c));
        CloseClient(c);
        NetSetErrno(E_NET_OK);
    }
    
    
    
    /* NetClientDataAvail()
     *--------------------------------------------------------------------
     * Returns the number of bytes available on the connection to a client.
     */
    int
    NetClientDataAvail(c)
         ClientPtr c;
    {
      long len;
      int fd = GetClientFd(c);
      int cnt;
    
      if(ioctl(fd, FIONREAD, &len))
        {
          
          return -1;
        }
    
      NetSetErrno(E_NET_OK);
      return len;
    }
    
    
    
    /* NetGetClientHostname()
     *--------------------------------------------------------------------
     * Gets the hostname of a remote client.
     *--------------------------------------------------------------------
     * Given a buffer ``hanme'' and the size of that buffer, ``maxhostlen'',
     * puts the hostname of the remote client into the buffer.
     *
     * Usually, the client's hostname will will be available through
     * @GetClientHname() if @GetClientMaxHlen() returns non-zero on the
     * client. If however, you have defined @GetClientMaxHlen() to return
     * zero, @GetClientHostname() is the function to call, since the
     * data will not be available through @GetClientHname().
     *
     * Returns a pointer to the buffer on success, or NULL on error.
     */
    char *
    NetGetClientHostname(c, hname, maxhostlen)
         ClientPtr c;
         char *hname;
         int maxhostlen;
    {
      struct sockaddr_in name;
      int nlen = sizeof(name);
    
      if(getpeername(GetClientFd(c), &name, &nlen))
        {
          NetSetErrno(E_NET_ERRNO);
          return NULL;
        }
    
      NetSetErrno(E_NET_OK);
      return AddrToHost(&name.sin_addr, hname, maxhostlen);
    }
    
    
    /* This is not for you. */
    static char *
    AddrToHost(struct in_addr *addr, char *hname, int maxhostlen)
    {
        struct hostent *hent;
    
        hent = gethostbyaddr(addr, sizeof(*addr), AF_INET);
        if(hent == NULL)
                /* Use the ip address as the hostname */
                strncpy(hname, inet_ntoa(*addr), maxhostlen);
        else
            strncpy(hname, hent->h_name, maxhostlen);
    
        return hname;
    }
    
    
    static void NetSetErrno(NetErrnoType e)
    {
      if(e == E_NET_ERRNO)saved_errno = errno;
      net_errno = e;
      if(net_errno != E_NET_OK) HandleNetError();
    }