#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/wait.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include "client.h"
#include "config.h"
#include "names.h"

struct sockaddr_in open_client(char *hostname, int host_port)
{
  int sockfd;
  struct hostent *he;
  struct sockaddr_in their_addr; /* connector's address information */  
  char *addr;

  if (config.use_DNS) {
    if ((he=gethostbyname(hostname)) == NULL) {  /* get the host info */
      perror("gethostbyname");
      exit(1);
    }
  } else {
    addr = get_address_by_name(hostname);
    if ((he=gethostbyname(addr)) == NULL) {
      perror("gethostbyname");
      exit(1);
    }
  }

  their_addr.sin_family = AF_INET;      /* host byte order */
  their_addr.sin_port = htons(host_port);    /* short, network byte order */
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero), 8);     /* zero the rest of the struct */

  return their_addr;
}

int open_connection(struct sockaddr *their_addr)
{
  int sockfd;
  struct sockaddr_in my_addr;
  int n;

  // open socket
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  // bind the client to a port
  if (config.client_port) {

    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&n , sizeof(int)) != 0) {
      fprintf(stderr, "Unable to set reuse address option\n");
    }

    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(config.client_port);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(my_addr.sin_zero), 8);
    
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
      perror("bind");
      exit(1);
    }
  }

  // open connection
  if (connect(sockfd, (struct sockaddr *)their_addr, sizeof(struct sockaddr)) == -1) {
      perror("connect");
      exit(1);
  }

  return sockfd;
}
