/*TESTO

Si realizzi in ambiente Unix/C il SERVER della seguente interazione tra processi:

- il sistema consiste di due processi: un processo server Ps e un processo cliente Pc; per la comunicazione tra Ps e i processi
cilenti Pcivengono utilizzate socket Stream; scegliere la porta su cui il sevrer offre il servizio: 789 o 7890 (motivare). Il
server crea un figlio e poi si pone in attesa dell'arrivo di dati dal client;
- il client invia una stringa testuale;
- il processo server la legge, la invia al figlio, che a sua volta la visualizza a video;
- se la stringa e' STOP il processo server fa terminate il processo figlio mediante l'invio di un segnale, e poi termina anch'esso;
altrimenti il server si rimette in attesa di dati dal client.

Come generico client Ps si suggerisce l'utilizzo del programma telnet, invocato come "telnet localhost numeroportaserver" 
(es. "telnet localhost 7890"). Attenzione che telnet attacca ad ogni stringa inviata la sequenza di caratteri "\r\n". 

Si siggerisce l'utilizzo delle funzionie C strcmp per verificare la presenza della parola chiave STOP.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>


#define PORT 7890


//Funzione di gestione segnali.
void handler()
{
  printf("\nProcesso %d esce",getpid());

  exit(0);
}



int main()
{
  char buffer[256]="";
  int pidFiglio;

  int p[2]; //la pipe

  struct sigaction sig;
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght;


  if(pipe(p)<0) //creo la pipe, sara' il canale di comunicazione tra padre e figlio
    {
      perror("pipe");
      exit(-1);
    }

  if((pidFiglio=fork())<0)  //creo il figlio che stampera' le stringhe
    {
      perror("fork figlio");
      exit(-1);
    }
  else
    if(pidFiglio==0) //sono il figlio?
      { 
	//FIGLIO
	printf("Sono il figlio con pid %d\n",getpid());

	close(p[1]); //chiudo il descrittore di scrittura della pipe, non mi serve

	//installo il gestore affidabile del segnale di uscita per tutti i processi
	//non e' strettamente necessario, il testo non lo chiedeva ed era sufficiente (e necessaria) una gestione non affidabile
	//lo metto giusto come ulteriore esempio (minimo) di gestione affidabile dei segnali
	sig.sa_handler = handler; 
	sigemptyset(&sig.sa_mask);
	sig.sa_flags=SA_RESTART;

	sigaction(SIGINT,&sig,NULL);

	do //ciclo infinito di lettura dalla pipe
	  {
	    if(read(p[0],buffer,sizeof(buffer))<0) //leggo la stringa che mi invia il sevrer
	      perror("read pipe");

	    printf("\nFiglio: ho ricevuto la stringa %s",buffer);
	  }
	while(1);
      }
    else //altrimenti sono il padre (server)
      {
	//PADRE
	printf("Sono il padre con pid %d\n",getpid());

	sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
	if(sock<0)
	  {
	    perror("creazione stream socket");
	    kill(pidFiglio,SIGKILL);
	    exit(-1);
	  }

	//preparo la struttura sockaddr_in per settare i parametri della socket
	server.sin_family=AF_INET;         //internet protocol
	server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
	server.sin_port=htons(PORT);       //e dalla porta specificata
	if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
	  {
	    perror("binding stream socket");
	    kill(pidFiglio,SIGINT);
	    exit(-1);
	  }

	lenght=sizeof(server);
	if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
	  {
	    perror("getting socket name");
	    kill(pidFiglio,SIGINT);
	    exit(-1);
	  }

	printf("Socket port # %d\n",ntohs(server.sin_port));

	listen(sock,5); //massimo di 5 connesioni in attesa

	msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
	if(msgsock == -1)
	  {
	    perror("accept");
	    exit(-1);
	  }

	do //questo e' il ciclo principale del server: legge i messaggi che gli manda il client e li gira al figlio
	  {	    
	    if(read(msgsock,buffer,sizeof(buffer))<0) //leggo il messaggio
	      perror("reading message");

	    if(!strncmp(buffer,"STOP\r\n",6))//se ricevo STOP uccido il figlio ed esco
	      {
		kill(pidFiglio,SIGINT); //uccido il figlio
		close(sock);
		close(msgsock);
		exit(0);
	      }	      

	    //mando la stringha ricevuta al figlio
	    if(write(p[1],buffer,sizeof(buffer))<0)
	      perror("writing message");
	  }
	while(1);
      }

  
  return 0;
}
