/* TESTO

Prova UNIX:
Si realizzi in ambiente Unix/C il server della seguente interazione tra processi:

-il sistema consiste di un processo server Ps e dei processi clienti Pci; per la
comunicazione tra Ps e i processi clienti Pci vengono utilizzate socket di tipo Stream;
la porta su cui il server Ps offre il servizio va scelta tra la 207 e la 2007, inserendo in
un commento la motivazione.

-il client invia al server una stringa che rappresenta un numero N con 1  N  4.

-il processo server Ps fornisce un servizio concorrente : il figlio creato per servire una
connessione deve creare N processi Pni che visualizzano il proprio PID e terminano;

-il client deve ricevere un messaggio di tipo stringa contenente i PID degli N processi
Pni;


Si consideri anche l'estensione di far generare a ciascuno degli N processi Pni un
numero casuale (rappresentato come stringa) che deve essere trasmesso al cliente insieme al
PID del processo. Come client si utilizzi il comando "telnet nomehost porta".
*/


/* NOTA
Il codice commentato e indicato con ESTENSIONE realizza la funzionalita' richiesta nell'estensione
del testo
 */

#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 2007 //le porte sotto il 1024 sono riservate al sistema operativo


int main()
{
  char buffer[256];
  int pidV[4]; //un vettore per i pid dei processi Pni, che saranno al massimo 4
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght,pid,N,i;

  /*ESTENSIONE
    int p[2],nrand;
  */

  //stampo il pid del 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");
      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");
      exit(-1);
    }
  printf("Server socket port # %d\n",ntohs(server.sin_port));

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

  //ciclo infinito del server concorrente
  do
    {
      printf("Accept nel server...\n");
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght); //attendo connesioni...
      if(msgsock == -1)
	{
	  perror("accept");
	  exit(-1);
	}

      if((pid=fork())<0)  //creo il figlio gestore della connessione
	{
	  perror("fork figlio");
	  exit(-1);
	}
      else
	if(pid==0) //sono il figlio?
	  {
	    //CODICE FIGLIO GESTORE
	    printf("Figlio gestore con pid %d\n",getpid());

	    //non mi serve piu' questo descrittore
	    close(sock);

	    /*ESTENSIONE
	      if(pipe(p)<0) 
	      {
	      perror("pipe");
	      exit(-1);
	      }
	    */

	    //ciclo del gestore: deve continuamente leggere dalla socket i messaggi che il Pclient gli manda
	    do
	      {
		if(read(msgsock,buffer,256)<0) //leggo il numero di processi Pni da creare
		  perror("reading message");

		N=(int)(buffer[0]-'0'); //lo metto in un numero
		if(N<1 || N>4) //e' un numero valido?
		  {
		    printf("Figlio %d : il cliente mi ha mandato il numero %d non valido, esco.\n",getpid(),N); 
		    exit(-1);
		  }

		printf("Figlio %d : il cliente mi ha mandato %d\n",getpid(),N); 
		sprintf(buffer,"Processi Pni ");

		//ciclo di creazione dei Pni
		for(i=0;i<N;i++)
		  {
		    if((pidV[i]=fork())<0)
		      {
			perror("fork figlio del gestore");
			exit(-1);
		      }
		    else
		      if(pidV[i]==0) //sono il figlio?
			{
			  //CODICE figlio Pni
			  close(msgsock); //non mi serve piu'
			  printf("Figlio del gestore %d con pid %d\n",getppid(),getpid());
			  /*ESTENSIONE
			    close(p[0]);
			    srand(getpid()); //inizializzo il generatore di numeri casuali
			    nrand=rand()%10; //numero casuale da 0 a 9
			    printf("Numero casuale di %d = %d\n",getpid(),nrand);
			    write(p[1],&nrand,sizeof(nrand));
			  */
			  exit(-1);
			}
		    /* ESTENSIONE
		       read(p[0],&nrand,sizeof(nrand)); //leggo dal figlio Pni il suo numero casuale
		       sprintf(buffer,"%s Pid=%d con numero casuale %d ",buffer,pidV[i],nrand);
		    */
		    sprintf(buffer,"%s Pid=%d ",buffer,pidV[i]); //da commentare nella versione con ESTENSIONE!!!
		  }
		printf("Figlio %d manda al clinent la stringa: %s\n",getpid(),buffer);
		if(write(msgsock,&buffer,strlen(buffer)+1)<0) //spedisco al client la risposta
		  perror("writing message");
	      }
	    while(1);//ciclo del figlio gestore della connessione
	  }

      //CODICE PADRE
      close(msgsock);
    }
  while(1);//ciclo del server padre

  return 0;
}
