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

#define PORT 8800
#define MAX_CONNECTION 6


int sockfd;
int newsockfd;

void error(const char *msg)
{
    perror(msg);
    exit(1);
}


void process_request(int newsockfd){
	char buffer[5000];
	int n;
	bzero(buffer,5000);
	//leemos del socket hasta 5000 bytes
	n = read(newsockfd,buffer,5000);
	if (n < 0) 
		error("ERROR reading from socket");

	//Si no hay contenido que leer salimos
         if(strlen(buffer)==0)
         {
                 close(newsockfd);
                 return;
         }

	/*****PRACTICA IMPLEMENTAR AQUI***/
/*
Para la correcta realización de las prácticas se incluyen las siguientes tareas que (al menos) deben realizarse dentro de la función process_request:

1 Obtener método, recurso y versión de la petición HTTP almacenada en la variable buffer. Se recomienda el uso de la función sscanf.
2 Comprobar que el método de la petición sea GET y la versión HTTP/1.1 o HTTP/1.0
3 Comprobar si el recurso que se solicita es /.
        3a Si es /, simplemente el recurso solicitado es el recurso por defecto (tal como se leyó en el fichero de configuración).
4 Se debe comprobar la existencia del recurso solicitado por el navegador. Para ello se recomienda el uso de la función stat.
     4a Si el recurso existe se debe devolver una cabecera HTTP 200 OK junto con el contenido del recurso (por ejemplo, web solicitada) solicitado.
         4aa Para construir la cabecera de respuesta se recomienda el uso de la función sprintf. El contenido del campo   Content-Length se obtendrá de la función stat (ver código de ayuda) mientras que el contenido del campo Content-Type se obtendrá del fichero de mimes (ver código de ayuda).
         4ab Para la lectura de los recursos (ficheros a enviar como respuesta) se debe hacer uso de la funcion fread y NO de la funcion fgets
     4b Si el recurso no existe se debe devolver una cabecera HTTP 404 Not Found que no contenga Content-Type ni Content-Length (mirar ejemplos enunciado, o Wireshark!).

*/


	printf("The message is: %s\n",buffer);

	/*************************************/
	//devolvemos la respuesta
	n = write(newsockfd,"I get the message\n",18);
	if (n < 0) 
		error("ERROR writing to socket");
	//cerramos el socket nuevo que se ha creado en el otro sentido
	close(newsockfd);
}

void handle(int nsignal){
	printf("server is shutting down now\n");
	close(sockfd);
	close(newsockfd);
	exit(0);
}

int main(int argc, char *argv[])
{
	int portN;
	struct sockaddr_in serv_addr,cli_addr;
	int n, newsockfd;

	// Crear un socket para manejar conexiones TCP
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) 
		error("ERROR opening socket");



	/*****PRACTICA IMPLEMENTAR AQUI***/

	/*Lectura de fichero de configuracion y asignacion de puerto a variable portN*/
	/* (ver código de ayuda) */
	/**********************************/

	// Preparar una estructura con informacion sobre como vamos
	// a recibir las conexiones TCP
	// En este ejemplo, enlazaremos el socket a la IP local al puerto TCP PORT
	// Esto lo conseguiremos inicializando
	// la estructura a cero mediante, por ejemplo, 'bzero'.
	bzero((char *) &serv_addr, sizeof(serv_addr));
	portN = PORT;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portN);
	

	// Activaremos una propiedad del socket que permitira que otros
	// sockets puedan reutilizar cualquier puerto al que nos enlacemos.
	// Esto permitira en protocolos como el TCP, poder ejecutar un
	// mismo programa varias veces seguidas y enlazarlo siempre al
	// mismo puerto. De lo contrario habria que esperar a que el puerto
	// quedase disponible (TIME_WAIT en el caso de TCP)
	if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&serv_addr,sizeof(struct sockaddr_in))==-1)
	{
 		error("ERROR: Fallo al reutilizar el puerto.\n");
	}

	if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
		error("ERROR on binding");

	/* Habilitar socket para recibir una conexion */
	if (listen(sockfd, MAX_CONNECTION) == -1){
		printf("Error en listen\n");
		close(sockfd);
		return -1;
	}

	/* Captura la senal SIGINT */
	if(signal(SIGINT,handle)==SIG_ERR)
	{
		error("ERROR: Fallo al capturar la senal SIGINT.\n");
	}

	/* While (true) */
	while (1){
		/* Espera de conexion */
		n = sizeof(struct sockaddr_in);
		if ((newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,(socklen_t *) &n)) == -1){
			printf("Error en accept\n");
			continue;
		}
		/* procesar peticion */
		process_request(newsockfd);
	}
	close(sockfd);
	return 0; 
}

