net.c


Index

  • strerror (returns const char *)
  • NetSetErrno (returns static void )
  • NetErrStr (returns const char *)
  • NetErrNo (returns NetErrnoType )
  • NetMakeContact (returns SOCKET )
  • xmit (returns int )

  • /* net.c: TCP/IP client code.
    
       To build a test-stub, compile with
    
       gcc -DTEST net.c
    
       Add a -DSTRERROR_NOT_DEFINED if strerror() doesn't exist on your machine.
    
       Once the program is compiled, try stuff like "./a.out xcf.berkeley.edu 79"
       and then enter "ali" followed by RETURN. Port 79 is the WHOIS or finger
       port.
    
       Or do "./a.out stanford.edu 25" and start forging mail. Port 25 is the
       sendmail port.
    
       The a.out produced behaves like a poor man's version of line-buffered
       telnet.
    */
    
    
    #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 <string.h>
    #include <errno.h>
    #include "net.h"
    
    
    static NetErrnoType net_errno = E_NET_OK;
    static int saved_errno = 0;
    
    /* Translations between ``net_errno'' values and human readable strings.
    */
    static char *net_syserrlist[] = {
            "All was chill"
    };
    
    
    
    
    #ifdef STRERROR_NOT_DEFINED
    const char *strerror(int errno) { return sys_errlist[errno]; }
    #endif
    
    static void NetSetErrno(NetErrnoType e)
    {
      if(e == E_NET_ERRNO)saved_errno = errno;
      net_errno = e;
    }
    
    
    
    /* 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;
    }
    
    /* NetMakeContact()
     *--------------------------------------------------------------------
     * Makes a tcp connection to a host:port pair.
     *--------------------------------------------------------------------
     * ``Hostname'' can either be in the form of a hostname or an IP address
     * represented as a string. If the hostname is not found as it is,
     * ``hostname'' is assumed to be an IP address, and it is treated as such.
     *
     * If the lookup succeeds, a TCP connection is established with the
     * specified ``port'' number on the remote host and a stream socket is
     * returned.
     *
     * On any sort of error, an error code can be obtained with @NetErrNo()
     * and a message with @NetErrStr().
     */
    SOCKET
    NetMakeContact(const char *hname, int port)
    {
      int fd;
      struct sockaddr_in addr;
      struct hostent *hent;
    
      fd = socket(AF_INET, SOCK_STREAM, 0);
      if(fd == -1)
        {
          NetSetErrno(E_NET_ERRNO);
          return -1;
        }
    
    
      hent = gethostbyname(hname);
      if(hent == NULL)
        addr.sin_addr.s_addr = inet_addr(hname);
      else
        memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
    
      if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)))
        {
          NetSetErrno(E_NET_ERRNO);
          return -1;
        }
    
      NetSetErrno(E_NET_OK);
      return fd;
    }
    
    
    
    #ifdef TEST
    
    int xmit(int fd1, int fd2)
    {
      int l;
      char iobuf[1024];
    
      l = read(fd1, iobuf, sizeof(iobuf));
      if(l<=0)return -1;
    
      l = write(fd2, iobuf, l);
      if(l<=0)return -1;
    
      return 0;
    }
    
    main(int argc, char **argv)
    {
      SOCKET s;
      fd_set readfds;
    
      if(argc != 3) {
        fprintf(stderr, "usage: %s hostname port\n", argv[0]); exit(-1);
      }
    
      s = NetMakeContact(argv[1], atoi(argv[2]));
      if(s==-1) {
        fprintf(stderr, "Network error: %s\n", NetErrStr()); exit(-1);
      }
    
      /* Make the socket non-blocking */
      ioctl(s, FIONBIO, 1);
    
    
      FD_ZERO(&readfds);
    
      for(;;)
        {
          FD_SET(0, &readfds);
          FD_SET(s, &readfds);
    
          if(select(s+1, &readfds, NULL, NULL, NULL) == -1) break;
    
          if(FD_ISSET(s, &readfds))
            if(xmit(s, 1)) break;
          if(FD_ISSET(0, &readfds))
            if(xmit(0, s)) break;
        }
    }
    
    
    #endif