#################################################################
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);
}
/*****************************************************************************/