#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <pthread.h>

#include "UDPoverTCPtunelClient.h"
#include "UDPoverTCPtunel.h"

int main(int argc, char * argv[]){
  int udpSocketId, tcpSocketId;
  
  /*UDPoverTCPtunelClient
    UDP_Local_Port
    TCP_Remote_Server_Host
    TCP_Remote_Server_Port
    UDP_Remote_Server_Host
    UDP_Remote_Port*/
  if(argc!=6){
    printf("Usage: %s [udp_local_port] [tcp_remote_host] [tcp_remote_port] [udp_remote_host] [udp_remote_port]\n",argv[0]);
    exit(-1);
  }
  
  //Inicia el servidor UDP (conexión hacia el cliente UDP)
  if((udpSocketId = initServerUDP(atoi(argv[1]))) < 0)
    exit(1);
  //Inicia el cliente TCP (conexión hacia el tunel)
  if((tcpSocketId = initClientTCP(argv[2], atoi(argv[3]))) < 0) 
    exit(1);
  
  //Carga los datos del Servidor Remoto
  loadServerData(argv[4],atoi(argv[5]));
  
  //Inicia el Tunel con los sockets creados
  if(startTunel(udpSocketId, tcpSocketId) < 0)
    printf("Ended with comunication errors!.\n");
  
  return 0;
}

/***************************************************************
 * Retorna un socket que conecta hacia el cliente UDP
 ***************************************************************/ 
int initServerUDP(int port){
  int sock, n, len;
  struct sockaddr_in name;

  // Crea el socket
  if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
    printf("Error on creating socket\n");
    return -1;
  }

  // Crea la direxión del servidor
  name.sin_family = AF_INET;
  name.sin_port = htons(port);
  name.sin_addr.s_addr = htonl(INADDR_ANY); /* Use the wildcard address.*/
  len = sizeof(struct sockaddr_in);

  // Asocia el socket con la dirección del servidor
  if(bind(sock, (struct sockaddr *) &name, len) < 0){
    printf("Error on binding\n");
    return -1;
  }
  
  //retorna el socket 
  return(sock);
}

/***************************************************************
 * Retorna un socket que conecta hacia el tunel TCP
 ***************************************************************/ 
int initClientTCP(char hostname[64], int port){
  int n, sock, len, rconn;
  char buf[BUFSIZE];
  struct hostent *hp;
  struct sockaddr_in name;
    
  /* Look up our host's network address.*/
  if((hp = gethostbyname(hostname)) == NULL){
    printf("Error on getting Hostname\n");
    return -1;
  }

  /* Create a socket in the INET domain.*/
  if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    printf("Error on creating socket\n");
    return -1;
  }

  /* Create the address of the server. */
  name.sin_family = AF_INET;
  name.sin_port = htons(port);
  memcpy(&name.sin_addr, hp->h_addr_list[0], hp->h_length);
  len = sizeof(struct sockaddr_in);

  /* Connect to the server. */
  if((rconn = connect(sock, (struct sockaddr *) &name, len))<0){
    printf("Error on doing connection\n");
    return -1;
  }
  
  return sock;
}
