/* socketkinds.h */

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

extern int errno;   
extern int h_errno; /* used with gethostbyname */

/* It opens a connection to the host name rhost that is listening
   on the specified port. It returns the socket descriptor, or -1
   in case of failure.
 */
int clientsocket(const char *rhost, unsigned short port)
{  
  struct hostent *ptrh;  /* pointer to a host table entry     */
  struct sockaddr_in sad;/* structure to hold server's address*/
  int    fd;             /* socket descriptor                 */

  memset((char *)&sad, 0, sizeof(sad)); /* clear sockaddr structure */
  sad.sin_family = AF_INET;  /* set family to Internet */
  sad.sin_port = htons((u_short)port);
  /* Convert host name to equivalent IP address and copy sad */
  ptrh = gethostbyname(rhost);
  if (((char *)ptrh) == NULL) {
    fprintf(stderr, "invalid host: %s, error: %d\n", rhost, h_errno);
    return (-1);
  }
  memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
    
  /* Create a socket */
  fd = socket(PF_INET, SOCK_STREAM, 0);
  if (fd < 0) {
    fprintf(stderr, "socket creation failed: %s\n", strerror(errno));
    return (-1);;
  }
    
  /* Connect the socket to the specified server */
  if (connect(fd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
    fprintf(stderr, "connect failed: %s\n", strerror(errno));
    return (-1);
  }
 
  return fd;
}


/* Create a server listening socket waiting on port 'port'
   with queue size 'qz'. It returns the listening socket
   or -1 in case of failure.
*/   
int listensocket(int port, int qz)
{
  int ls;
  int option_value;   /* needed for setsockopt             */
  struct sockaddr_in serv;
  
  ls = socket(AF_INET, SOCK_STREAM, 0);
      
  memset((char *)&serv, 0, sizeof(serv)); /* clears out buffer of this size*/
  serv.sin_family = AF_INET;
  serv.sin_port = htons((u_short)port); /* 80 */
  serv.sin_addr.s_addr = htonl(INADDR_ANY); /* any interface ????*/
  
  /* Make listening socket's port reusable - must appear before bind */
  option_value = 1;
  if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value,
                 sizeof(option_value)) < 0) {
     perror("setsockopt failure");
     return -1;
  }

  /* Bind a local address to the socket */
  if (bind(ls, (struct sockaddr *)&serv, sizeof(serv)) < 0) {
    fprintf(stderr, "bind failed, port: %d, error: %s\n",port,strerror(errno));
    return -1;
  }
  
  /* Specify size of request queue */
  if (listen(ls, qz) < 0) {
    fprintf (stderr, "listen failed, port: %d, error: %s\n", 
	     port, strerror(errno));
    return -1;
  }
                 
  return ls;
} 


/* Return a connected socket obtained by an accept call
   on the listening socket lsd.
 */
int connectedsocket ( int lsd )
{
  int                 csd;
  size_t              clilen;
  struct sockaddr_in  cliaddr;
  
  while (1) {
    clilen = sizeof(cliaddr);
    if ( (csd = accept(lsd, (struct sockaddr *) &cliaddr,
                          (int *)&clilen)) >= 0)
      break;
    if (errno != EINTR) { /* accept was not interrupted by a signal */
      fprintf(stderr, "accept failure, error: %s\n", strerror(errno));
      return -1;
    }
  }
  return csd;
}
