Contents
#################################################################
Programma della conferenza distribuita

Copyright (C) 19aa  
Autori: Andrea Lanzi, Giampaolo Fresi Roglia

Questo programma e' software  libero; e' lecito ridistribuirlo e/o
modificarlo secondo i  termini della Licenza Pubblica Generica GNU
come pubblicata  dalla Free Software Foundation;   o la versione 2
della licenza o (a scelta) una versione successiva.
Questo programma e' distribuito  nella speranza che sia utile,  ma
SENZA  ALCUNA GARANZIA;  senza  neppure la  garanzia  implicita di
COMMERCIABILITA o di APPLICABILITA PER UN PARTICOLARE SCOPO.  Si
veda la Licenza Pubblica Generica GNU per avere maggiori dettagli.
Ognuno dovrebbe avere  ricevuto una copia  della Licenza Pubblica
Generica GNU insieme a questo programma; in  caso contrario, la si
puo' ottenere dalla Free Software  Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, Stati Uniti.
Gli autori possono essere contattati ai seguenti indirizzi:

Andrea Lanzi           : shadow.net@tiscalinet.it
Giampaolo Fresi Roglia : gian_fresi@iol.it

##################################################################


#include "client_subs.h"
#include "messages.h"


//PROCEDURA PER LA GESTIONE DELLA CONSERVAZIONE
int gest_conv (int coord_sock)
{
  partecipanti *temp, *lista;
  char buf[MAX_DIM];
  char *str_ind;
  int num_cli=0, porta, sock_cli,n,ris, tempfd;
  fd_set afds,rfds;  
  int fine_input = 0; 
  #ifdef UNBUFFERED
     int	invio = 0;
  #endif
  unsigned long indirizzo;
  struct sockaddr_in cli_addr;
  int REM_GUEST = _REM_GUEST;
  int ADD_GUEST = _ADD_GUEST;
  #ifdef UNBUFFERED
     struct termios old_term_options;
  #endif

  // PROCEDURA CHE SETTA L'INPUT NON BUFFERIZZATO
  #ifdef UNBUFFERED
     set_term_unbuf(&old_term_options);
  #endif
  
  //INIZIALIZZAZIONE DELLE VARIE STRUTTURE
  mk_list(&lista);
  num_cli=init_conv(coord_sock, &lista);
  FD_ZERO( &afds );
  FD_SET(coord_sock, &afds);
  FD_SET(0, &afds);
  
  // QUESTO CICLO INIZIALIZZA LA STRUTTURA UTILIZZATA DALL'ORATORE
  // CORRENTE PER LA CONVERSAZIONE CON GLI ALTRI PARTECIPANTI
  // APRENDO UNA SOCKET CON OGNUNO.
  temp=lista;
  while(temp!=NULL)
  {
     bzero((char *) &cli_addr, sizeof(cli_addr));
     cli_addr.sin_family = AF_INET;
     cli_addr.sin_addr.s_addr = temp -> indirizzo;
     cli_addr.sin_port = htons (temp -> porta);
     if((sock_cli = socket(AF_INET, SOCK_STREAM, 0))<0)
     {
        perror("socket");
        rm_cli(&lista, temp -> indirizzo, temp -> porta);
     }
     else{
     if(connect(sock_cli, (struct sockaddr *) &cli_addr, sizeof(cli_addr))<0)
     {
        perror("connect");
        tempfd=rm_cli(&lista, temp -> indirizzo, temp -> porta);
        close(tempfd);
      }
      else
      {
         temp -> fd = sock_cli;
      }
      }
      temp = temp -> next;
   }
   
   // QUESTO CICLO LEGGE DALLO STANDARD INPUT DELL'ORATORE 
   // L'INTERVENTO E LO INVIA A TUTTI I PARTECIPANTI

   printf("Per terminare l'intervento premere ENTER su riga vuota\n");

   while(!fine_input)
   {
      bcopy( (char*) &afds, (char*) &rfds, sizeof(rfds) ) ;
      if(select( FOPEN_MAX, &rfds, NULL, NULL, NULL) < 0 )
         perror("select");
         
      // GESTIONE DELLO STANDARD INPUT
      if(FD_ISSET(0, &rfds))
      {
         n=read(0,buf,MAX_DIM);
         buf[n]='\0';
	 if(write(coord_sock,buf,n)<=0)
         {
            printf("\npersa connessione col coordinatore\nesco\n");
            exit(-1);
         }
	 temp=lista;
	 while(temp!=NULL)
         {
	    if((write(temp -> fd, &buf, n))!=n)
	    {
               indirizzo=temp ->indirizzo;
               porta=temp ->porta;
	       temp=temp-> next;
	       tempfd = rm_cli(&lista, indirizzo, porta);
               close(tempfd);
	    }
	    else
	       temp=temp->next;
	 }
         // GESTIONE DELLA CHIUSURA  DELL''INTERVENTO
         #ifdef UNBUFFERED
            if(buf[n-1]!=10)
               invio = 0;
               else	invio++;
            if (invio == 2)
               fine_input=1;
         #else
            if(strcmp(buf,"\n")==0)
               fine_input=1;
         #endif   
      }
      
      // GESTIONE DELLA COMUNICAZIONE CON IL COORDINATORE
      if(FD_ISSET(coord_sock, &rfds))
         {
            if((read(coord_sock, &ris, sizeof(ris)))<=0)
            {
               printf("\npersa connessione col coordinatore\nesco\n");
               exit(0);
            }
            
            // CANCELLAZIONE DI UN NUOVO PARTECIPANTE
	    if(ris==REM_GUEST)
	    {
               read(coord_sock, &indirizzo, sizeof(indirizzo));
               read(coord_sock, &porta, sizeof(porta));
               bzero((char *) &cli_addr, sizeof(cli_addr));
               cli_addr.sin_addr.s_addr = indirizzo;
               str_ind=inet_ntoa(cli_addr.sin_addr);
               tempfd=rm_cli(&lista, indirizzo, porta);
               close(tempfd);
            
               printf("\nDisconnessione di: %s:%d\n",str_ind, porta);
	    }
	    else
            // INSERIMENTO DI UN NUOVO PARTECIPANTE
	    if(ris==ADD_GUEST)
	    {
	       read(coord_sock,&indirizzo,sizeof(indirizzo));
	       read(coord_sock,&porta,sizeof(porta));
               bzero((char *) &cli_addr, sizeof(cli_addr));
	       cli_addr.sin_family=AF_INET;
	       cli_addr.sin_addr.s_addr=indirizzo;
	       cli_addr.sin_port=htons ( porta );
               str_ind=inet_ntoa(cli_addr.sin_addr);
               printf("\nAggiunta partecipante: %s:%d\n", str_ind, porta);
	       sock_cli = socket(AF_INET,SOCK_STREAM,0);
	       connect( sock_cli, (struct sockaddr *) &cli_addr, sizeof( cli_addr));
	       add_cli(&lista, sock_cli, indirizzo, porta);
	    }
         }
   }
   printf("\nFine messaggio\n");
   while(lista != NULL)
   {
      rm_cli(&lista, 0, 0);
   }
   
   // SETTA L'INPUT NON BUFFERIZZATO 
   #ifdef UNBUFFERED
      set_term_buf(old_term_options);
   #endif

   return 0;
}
/*****************************************************************************/
// AGGIUNGE UN ELEMENTO ALLA LISTA  DELL''ORATORE CORRENTE
int add_cli (struct lista_ind **lista, int sockfd, unsigned long indirizzo, 
        	int porta)
{
   partecipanti *nuovo;
   if((nuovo = malloc(sizeof( partecipanti )))==NULL)
   {
         perror("malloc");
         return -1;
   }       
   nuovo -> next = (*lista);
   nuovo -> prec = NULL;
   if ((*lista) != NULL) 
      (*lista) -> prec = nuovo;
   nuovo -> fd = sockfd;
   nuovo -> indirizzo = indirizzo;
   nuovo -> porta = porta;     
   (*lista) = nuovo;
   return 0;
}

/******************************************************************************/
// RIMUOVE UN ELEMENTO ALLA LISTA DELL''ORATORE CORRENTE
int rm_cli (struct lista_ind **lista, int indirizzo, int porta)
{
   struct lista_ind *temp;
   int fd;
   temp=*lista;
   while(temp!=NULL)
   {
      if(((temp -> indirizzo == indirizzo)&&(temp -> porta == porta))
         	||(indirizzo == 0))
      {
         if(temp==*lista)
            *lista = temp -> next;
         fd=temp -> fd;
         if ( temp -> prec != NULL)
            temp -> prec -> next = temp -> next;
         if ( temp -> next != NULL)
            temp -> next -> prec = temp -> prec;
         free ( temp );
         return fd;
      }
      else
         temp=temp -> next;
   }
   return -1;
}

/******************************************************************************/
//INIZIALIZZA LA LISTA    
int mk_list (struct lista_ind **lista) 
{ 
    *lista = NULL ;
    return 0;
}

/*****************************************************************************/
//INIZIALLIZZA LA LISTA DELL''ORATORE CORRENTE CON GLI INDIRIZZI INVIATI DAL 
//SERVER    
int init_conv (int sockfd, struct lista_ind **lista)
{
   int num_cli, i;
   int porta;
   struct in_addr addr;
   unsigned long address;      
   
   read (sockfd, &num_cli, sizeof(num_cli));
   
   // LEGGE I DATI DEGLI ALTRI PARTECIPANTI INVIATI DAL SERVER 
   for (i=0; i<num_cli; i++)
   {
       read(sockfd, &address, sizeof(address));
       read(sockfd, &porta, sizeof(porta));       
       add_cli(lista, 0, address, porta);
       addr.s_addr=address;   
       
   }
   return (num_cli);
}
/*****************************************************************************/       
//ISCRIZIONE DI UN PARTECIPANTE ALLA CONFERENZA

int iscrizione (char HOST_ADDR[], int coord_port, int *coord_sock, 
        	int *serv_sock)
{

   int LOGON = _LOGON;
   int ACK = _ACK;
   int port=10000, ris;
   
   //CERCA UNA PORTA LIBERA DA UTILIZZARE
   while ((*serv_sock = passive_socket(port, 10)) < 0)
   {
      port++;
   }   
   
   //SOCKET ATTIVA CON IL COORDINATORE   
   if ((*coord_sock = active_socket(coord_port, HOST_ADDR)) < 0)
   {
      perror("active_socket");
      close(*serv_sock);
      return(-1);
   }      
   
   
   printf("\nconnessione al coordinatore per iscrizione...\n");
   write(*coord_sock, &LOGON, sizeof(LOGON)) ;
   write(*coord_sock, &port, sizeof(port)); 
   read(*coord_sock, &ris, sizeof(ris)) ;
   
   // LA CONNESSIONE E'' STATA ACCETTATA                         
   if (ris==ACK){
      printf("Ricevuto ACK dal coordinatore\nsono iscritto alla conferenza\n");
    }   
    else return -1;
    
    return 0;
}    
    
/*****************************************************************************/
// MENU PER LE OPERAZIONI DEL CLIENT
void menu()
{

   printf("\n*********************** M E N U' ***************************\n");
   printf("Fai la tua scelta : \n");
   printf("\n1 - Iscrizione alla conferenza \n");
   printf("\n2 - Iscrizione a parlare \n");
   printf("\n3 - Rinuncia a parlare \n");
   printf("\n4 - Rinuncia all'iscrizione \n");
   printf("\n5 - Esci \n");
   printf("\nScelta: \n");
}

/*****************************************************************************/
//ISCRIZIONE A PARLARE
int iscr_parl(int sockfd)
{
   int ris;
   int REQ_TALK = _REQ_TALK;
   int ACK = _ACK;
   
   printf("Richiesta di prenotazione a parlare...\n"); 
   write(sockfd, &REQ_TALK, sizeof(REQ_TALK));
   read(sockfd, &ris, sizeof(ris));
   if (ris == ACK)
   {
       printf("E' arrivato ACK dal coordinatore\nLa prenotazione a parlare e' stata accettata\n");
       return 1;
    }
    else return -1;
}

/*****************************************************************************/
// RINUNCIA A PARLARE
int rinuncia (int sockfd)
{
   int ris;
   int NOT_TALK = _NOT_TALK;
   int ACK = _ACK;

   printf("Rinuncia al diritto di parola...\n");
   write(sockfd, &NOT_TALK, sizeof(NOT_TALK));
   read(sockfd, &ris, sizeof(ris));
   if (ris == ACK)
   {         
      printf("E' arrivato ACK dal coordinatore\nLa rinuncia e' stata accettata\n");
      return 1;
   }
   else return -1;
}

/******************************************************************************/
//DISCONNESSIONE DALLA CONFERENZA
int disconnetti(int sockfd)
{
   int ris;
   int n=0;
   int LOGOFF = _LOGOFF;
   int ACK = _ACK;
      
   printf("Richiesta di uscita dalla conferenza...\n");
   write(sockfd, &LOGOFF, sizeof(LOGOFF));
   while(n==0)
      n=read(sockfd, &ris, sizeof(ris));
   
   if (ris == ACK)
   {
    printf("E' arrivato ACK dal coordinatore\nRichiesta di uscita accettata\n");
      return 1;
   }
   else return -1;
}

/*******************************************************************************/                  
// APERTURA DELLA SOCKET PASSIVA
int passive_socket(int port, int backlog){


        int sockfd;
        struct sockaddr_in serv_addr ;
        
	
        /*   Apre una socket TCP                                           */
        
	if( ( sockfd = socket( AF_INET, SOCK_STREAM, 0) ) < 0 )
        {
           return -1;
        }

	/* Bind del nostro indirizzo locale   */

	bzero( (char * ) &serv_addr, sizeof(serv_addr) ) ;
	
	serv_addr.sin_family = AF_INET ;
	serv_addr.sin_addr.s_addr = htonl( INADDR_ANY ) ;
	serv_addr.sin_port = htons( port ) ;
        
	if (bind( sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr))<0)
        {
           close(sockfd);
           return -1;
        }
                
        /* Ascolta sulla porta specificata */

   	listen(sockfd, backlog) ;
        
        return( sockfd ) ;
   
}
/******************************************************************************/
//APERTURA SOCKET ATTIVA
int active_socket(int port, char *host ){

int 	sockfd ; 
struct  sockaddr_in serv_addr ;
        

	/* Riempe la struttura serv_addr con l'indirizzo del server */

	bzero( (char *) &serv_addr, sizeof(serv_addr) ) ;

	serv_addr.sin_family = AF_INET ;
	serv_addr.sin_addr.s_addr = inet_addr( host ) ;
	serv_addr.sin_port = htons( port ) ;
	
	if(( sockfd = socket( AF_INET, SOCK_STREAM, 0)) < 0  )
           {
		perror("socket") ;
                return -1;
           }
		/* Si connette al server */

	
	if( connect( sockfd, (struct sockaddr *) &serv_addr, 
                	sizeof( serv_addr )) <0)
           {
		perror("connect") ;
                return -1;
           }    

   return( sockfd ) ;

}
/******************************************************************************/
// USATA PER SETTARE INPUT NON BUFFERIZZATO
void set_term_unbuf(struct termios *old_term_options)
{
        struct termios term_options;
        tcgetattr(0, old_term_options);
        term_options = *old_term_options;
        term_options.c_lflag &= !ICANON;
	term_options.c_lflag |= ECHO;
        term_options.c_cc[VTIME] = 0;
        term_options.c_cc[VMIN] = 1;
        tcsetattr(0, TCSANOW, &term_options);
}
/******************************************************************************/
// USATA PER SETTARE INPUT BUFFERIZZATO
void set_term_buf(struct termios term_options)
{
        tcsetattr(0, TCSANOW, &term_options);
}
/*****************************************************************************/