The Open Source Swiss Army Knife

/code/c/unix_c/socket_libs/
/code/c/unix_c/socket_libs/ + sub-categories
http://www.sirfsup.com/
web directory content
    
      

Not logged in
Chat Register Login
return to:  http:/www.sirfsup.com      /code   /c   /unix_c   /socket_libs 
Permalink: networkinglib.c
Title: http://www.complete.org/publications/lpb/downloads/lpb-examples
article options : please login   |  raw source view  

/*
Library for:
 * general networking
 * sockets, pipes, etc.
 * unbuffered I/O
 * other items relating to the above

by John Goerzen, Linux Programming Bible
*/

#include <ctype.h>
#include <stdlib.h>
#include "networkinglib.h"

static int checkstring(const char *string);

/* checkstring() is a private function used only by this library.  It checks
    the passed string.  It returns false if there are no nonnumeric
    characters  in the string, or true if there are such characters. */

static int checkstring(const char *string) {
int counter;
  for (counter = 0; counter < strlen(string); counter++)
    if (!(isdigit(string[counter])))
      return 1;
  return 0;
}

/* Send a string, including terminating null.  readdelimstring() could be
   perfect for reading it on the other end.  And in fact, readstring()
   uses just that. */

int writestring(int sockid, char *str) {
  return write_buffer(sockid, str, strlen(str) + 1);
}

/* Reads a string from the network, terminated by a null. */

int readstring(int sockid, char *buf, int maxlen) {
  return readdelimstring(sockid, buf, maxlen, 0);
}

/* Reads a string terminated by a newline */

int readnlstring(int sockid, char *buf, int maxlen) {
  return readdelimstring(sockid, buf, maxlen, '\n');
}

/* Reads a string with an arbitrary ending delimiter. */

int readdelimstring(int sockid, char *buf, int maxlen, char delim) {
  int count = 0, status;

  while (count <= maxlen) {
    status = saferead(sockid, buf+count, 1);
    if (status < 0) return status;
    if (status < 1) {
      HandleError(0, "readdelimstring", "unexpected EOF from socket");
      return status;
    }
    if (buf[count] == delim) {            /* Found the delimiter */
      buf[count] = 0;
      return 0;
    }
    count++;
  }
  return 0;
}

/* Copies data from the in to the out file descriptor.  If numsize
   is nonzero, specifies the maximum number of bytes to copy.  If
   it is 0, data will continue being copied until in returns EOF. */

int copy(int in, int out, unsigned long maxbytes) {
  char buffer[COPY_BUFSIZE];
  int indata, remaining;

  remaining = maxbytes;

  while (remaining || !maxbytes) {
    indata = saferead(in, buffer,
             (!remaining || COPY_BUFSIZE < remaining) ? COPY_BUFSIZE
              : remaining);
    if (indata < 1) return indata;
    write_buffer(out, buffer, indata);
    if (maxbytes) remaining -= indata;
  }
  return (0);
}


/*
   This function will write a certain number of bytes from the buffer
   to the descriptor fd.  The number of bytes written are returned.
   This function will not return until all data is written or an error
   occurs.
*/

int write_buffer(int fd, char *buf, int count) {
  int  status = 0, result;

  if (count < 0) return (-1);
 
  while (status != count) {
    result = safewrite(fd, buf + status, count - status);
    if (result < 0) return result;
    status += result;
  }
  return (status);
}

/*
   This function will read a number of bytes from the descriptor fd.  The
   number of bytes read are returned.  In the event of an error, the
   error handler is returned.  In the event of an EOF at the first read
   attempt, 0 is returned.  In the event of an EOF after some data has
   been received, the count of the already-received data is returned.
*/

int read_buffer(int fd, char *buf, int count) {
  char *pts = buf;
  int  status = 0, n;

  if (count < 0) return (-1);

  while (status != count) {
    n = saferead(fd, pts+status, count-status);
    if (n < 0) return n;
    if (n == 0) return status;
    status += n;
  }
  return (status);
}

/* Reads a uint32 from the network in network byte order.

   A note on the implementation: because some architectures cannot
   write to the memory of the integer except all at once, a character
   buffer is used that is then copied into place all at once. */

int read_netulong(int fd, uint32_t *value) {
  char buffer[sizeof(uint32_t)];
  int status;

  status = read_buffer(fd, buffer, sizeof(uint32_t));
  if (status != sizeof(uint32_t)) {
    HandleError(0, "read_netulong", "unexpected EOF");
    return -1;
  }
  bcopy(buffer, (char *)value, sizeof(uint32_t));
  *value = ntohl(*value);
  return (0);
}

/* Write an unsigned long in network byte order */

int write_netulong(int fd, const unsigned long int value) {
  char buffer[sizeof(uint32_t)];
  uint32_t temp;
  int status;

   temp = htonl(value);
   bcopy((char *)&temp, buffer, sizeof(temp));
   status = write_buffer(fd, buffer, sizeof(temp));
   if (status != sizeof(temp)) return -1;
   return (0);
}

/* Returns the fully qualified domain name of the current host. */
char *getmyfqdn(void) {
  char hostname[200];
  gethostname(hostname, sizeof(hostname));
  return getfqdn(hostname);
}

/* Returns the fully qualified domain name of an arbitrary host. */
char *getfqdn(const char *host) {
  struct hostent *hp;
  static char fqdn[200];
 
  hp = gethostbyname(host);
  if (!hp)
    return (char *)NULL;
  safestrncpy(fqdn, (hp->h_aliases[0]) ? hp->h_aliases[0] : hp->h_name,
              sizeof(fqdn));
  return fqdn;
}

void socketaddr_init(struct sockaddr_in *socketaddr) {
  bzero((char *) socketaddr, sizeof(*socketaddr));
  socketaddr->sin_family = AF_INET;
}

int socketaddr_service(struct sockaddr_in *socketaddr,
                       const char *service, const char *proto) {
  struct servent *serviceaddr;

  /* Need to allow numeric as well as textual data. */

  /* 0: pass right through. */

  if (strcmp(service, "0") == 0)
    socketaddr->sin_port = 0;
  else {                           /* nonzero port */
    serviceaddr = getservbyname(service, proto);
    if (serviceaddr) {
      socketaddr->sin_port = serviceaddr->s_port;
    } else {                      /* name did not resolve, try number */
      if (checkstring(service)) { /* and it's a text name, fail. */
        HandleError(0, "socketaddr_service", "no lookup for %s/%s",
                    service, proto);
        return -1;
      }
      if ((socketaddr->sin_port = htons((u_short)atoi(service))) == 0) {
        HandleError(0, "socketaddr_service", "numeric conversion failed");
        return -1;
      }
    }
  }

  return 0;
}

int socketaddr_host(struct sockaddr_in *socketaddr,
                    const char *host) {
  struct hostent *hostaddr;
  hostaddr = gethostbyname(host);
  if (!hostaddr) {
    HandleError(0, "socketaddr_host", "gethostbyname failed for %s", host);
    return -1;
  }

  memcpy(&socketaddr->sin_addr, hostaddr->h_addr, hostaddr->h_length);
  return 0;
}

int resolveproto(const char *proto) {
  struct protoent *protocol;
  protocol = getprotobyname(proto);
  if (!protocol) {
    HandleError(0, "resolveproto", "getprotobyname failed for %s", proto);
    return -1;
  }

  return protocol->p_proto;
}

int prototype(const char *proto) {
  if (strcmp(proto, "tcp") == 0) return SOCK_STREAM;
  if (strcmp(proto, "udp") == 0) return SOCK_DGRAM;
  return -1;
}

int clientconnect(const char *host, const char *port, const char *proto) {
  struct sockaddr_in socketaddr;
  int sockid;
 
  socketaddr_init(&socketaddr);
  socketaddr_service(&socketaddr, port, proto);
  socketaddr_host(&socketaddr, host);

  sockid = socket(PF_INET, prototype(proto), resolveproto(proto));
  if (sockid < 0) {
    HandleError(errno, "clientconnect", "socket failed");
    return -1;
  }

  if (connect(sockid, &socketaddr, sizeof(socketaddr)) < 0) {
    HandleError(errno, "clientconnect", "connect failed");
    return -1;
  }

  return sockid;
}

int serverinit(const char *port, const char *proto) {
  struct sockaddr_in socketaddr;
  int mastersock;
  int trueval = 1;

  socketaddr_init(&socketaddr);
  socketaddr.sin_addr.s_addr = INADDR_ANY;
  socketaddr_service(&socketaddr, port, proto);
 
  mastersock = socket(PF_INET, prototype(proto), resolveproto(proto));
  if (mastersock < 0) {
    HandleError(errno, "serverinit", "couldn't create socket");
    return -1;
  }

  if (bind(mastersock, &socketaddr, sizeof(socketaddr)) < 0) {
    HandleError(errno, "serverinit", "bind to port %d failed",
                socketaddr.sin_port);
    return -1;
  }

  setsockopt(mastersock, SOL_SOCKET, SO_REUSEADDR, &trueval, sizeof(trueval));

  if (prototype(proto) == SOCK_STREAM) {
    if (listen(mastersock, 5) < 0) {
      HandleError(errno, "serverinit", "listen on port %d failed",
                  socketaddr.sin_port);
      return -1;
    }
  }

  return mastersock;
}

/* Removes CR and LF from the end of a string. */
void stripcrlf(char *temp)
{
  while (strlen(temp) &&
         ((temp[strlen(temp)-1] == 13) || (temp[strlen(temp)-1] == 10))) {
    temp[strlen(temp)-1] = 0;
  }
}

Leave a Reply
Your Name:     anonymous
Your Email:
Website:  
Comments:

The author will be notified of your reply.
return to top