Come detto in precedenza questo elemento del progetto č stato inserito col duplice scopo di realizzare la funzionalitŕ di aggiornamento del DB dei STs presenti in rete e di investigatore del servizio con lo scopo di individuare 'chi c'č e dove '.
Descrizione sommaria del comportamento:
Codice.
/* Inizialmente il TERM effettua un Bcast sulla porta Bcast dei NS per determi nare il numero di NS attivi, che indirettamente da' un' idea dello stato del servizio, dopodiche' si rivolge alla loro porta TERM per ottenere da loro lo stato del servizio (soluzione distribuita rispetto all' uso della memoria condivisa). Chiaramente affinche' l'implementazione del servizio sia corretta e' neces sario che entrambi i NS diano la stessa immagine. */ #include "start.h" /*contiene i file di inclusione e le strutture dei semafori*/
void funct_replies(); void child_replies(); void alrm_child(); void alrm_father(); void state_service(); void updata(int); void extreme();
struct sockaddr_in baddr, /*socket b_cast datagram*/ termaddr, /*socket dgram che riceve lo stato del servizio*/ repaddr; /*socket dgram che riceve le risposte al b_cast*/
int i,shmid_index,semid,shmid_tab,t_out,bsock,termsock,repsock,crash, nobody;
sigset_t mask; MSG_EL msg_temp; fd_set read_mask,temp_mask; MSG_EL*ptr_own;
main(argc,argv) int argc; char* argv[]; { char answer;
clear_screen();
/*DEFINIZIONE del segmento di memoria condivisa del terminale*/ shmid_tab=shmget(SHMKEY_TAB_TERM,sizeof(TUPLA[2]),PERM|IPC_CREAT); ptr_tab_term=(TUPLA(*)[2])shmat(shmid_tab,(TUPLA(*)[2])0,0); memset((TUPLA(*)[2])ptr_tab_term,0,sizeof(TUPLA[2]));
ptr_own=(MSG_EL*)malloc(sizeof(MSG_EL)); memset((MSG_EL*)ptr_own,0,sizeof(MSG_EL)); gethostname(ptr_own->host_NS,sizeof(ptr_own->host_NS)); ptr_own->porta_replies=PORTA_TERM_RPLS; ptr_own->stato_NS=5; /*valore identificativo del terminale*/
/*l'aggirnamento č compiuto da un'unica funzione alla quale viene passato un parametro che consente di discriminare tra INSERIMENTO e ELIMINAZIONE*/
if(connection(&baddr,&bsock,0,PORTA_BCAST_EL,'B',stderr)) {fprintf(stderr,"errore nella creazione della socket B_CAST\n"); exit(0);}
for(;;) { clear_screen(); fprintf(stderr,"\n\n\t1 -> STATO DEL SERVIZIO"); fprintf(stderr,"\n\n\t2 -> INSERIMENTO NUOVE UTENZE"); fprintf(stderr,"\n\n\t3 -> ELIMINAZIONE VECCHIE UTENZE"); fprintf(stderr,"\n\n\t4 -> uscita"); fprintf(stderr,"\n\n\n\n\tDigita l' opzione "); answer=getchar();getchar(); switch(answer) { case '1': nobody=1;t_out=0;state_service(argv);break; case '2': updata(1);break; case '3': updata(-1);break; case '4': clear_screen(); semctl(semid,0,IPC_RMID,0); shmdt((char *)ptr_tab_term); shmctl(shmid_tab,IPC_RMID,(struct shmid_ds *)0); shmdt((char *)ptr_index); shmctl(shmid_index,IPC_RMID,(struct shmid_ds *)0); exit(0); default : fprintf(stderr,"\n\topzione errata. Preni invio per tornare al \ menů principale...");getchar(); } } }
/*****************************************************************************/ /* state_service() */ /*****************************************************************************/ void state_service() { clear_screen();
sigemptyset(&mask); sigaddset(&mask,SIGALRM); signal(SIGCLD,SIG_IGN); signal(SIGALRM,alrm_father);
if(make_socket(&repaddr,&repsock,ptr_own->porta_replies,'D',stderr)) {fprintf(stderr,"fallita la creazione della socket B_CAST d'ascolto\n"); exit(1);}
if(sendto(bsock,ptr_own,sizeof(MSG_EL),0,(struct sockaddr *)&baddr,len)<0) fprintf(stderr,"fallito l'invio del b_cast alla ricerca di un NS\n");
FD_ZERO(&read_mask); FD_SET(repsock,&read_mask); temp_mask=read_mask;
alarm(10);
fprintf(stderr,"\n\nRICERCA DEI NS PRESENTI IN RETE..."); do { select(repsock+1,&read_mask,NULL,NULL,NULL); if(FD_ISSET(repsock,&read_mask)) funct_replies(); read_mask=temp_mask; } while(!t_out);
if(nobody) { fprintf(stderr,"NESSUN NS A REGIME !\n"); memset((TUPLA(*)[2])ptr_tab_term,0,sizeof(TUPLA[2])); }
fprintf(stderr,"\n\n\n\tpremi invio per tornare al menů principale..."); getchar();close(repsock); return; }
/*****************************************************************************/ /* funzione che gestisce la ricezione delle risposte al BCAST */ /*****************************************************************************/ void funct_replies() {
/*Questa funzione per ogni risposta ricevuta genera un figlio che si occupa di ottenere dal NS che ha risposto lo stato del servizio. Supponiamo per ora che i figli (al massimo 2) memorizzino il messaggio ricevuto dal NS (che rappresenta lo stato delservizio) nella stessa area di memoria globale, gestita MUTEX e che l' unico modo per controllare la consistenza del sistema sia " l'uscita a video ". Questo penso sia un 'non' controllo accettabile considerando il fatto che il NS di NIRROR non ha una propria coscenza dello stato del servizio ma la acquisisce dal NS EFFETTIVO che periodicamente glielo invia.*/
int pid;
if(crash) {crash=0;return;} sigprocmask(SIG_BLOCK,&mask,NULL);
if(recvfrom(repsock,&msg_temp,sizeof(MSG_EL),0,(struct sockaddr *)0,(int*)0)<0) {fprintf(stderr,"%s:fallita la ricezione della risposta al b_cast\n", strerror(errno));return;} fprintf(stderr,"\n\n risposta al BCAST ricavuta da: "); switch(msg_temp.stato_NS) { case 0: fprintf(stderr,"NS in ELEZIONE ");break; case 1: fprintf(stderr,"NS MIRROR ");break; case 2: fprintf(stderr,"NS EFFETTIVO ");break; case 3: fprintf(stderr,"NS EFFETTIVO 'riflesso' "); } fprintf(stderr," su %s\n",msg_temp.host_NS); if(!msg_temp.stato_NS) {sigprocmask(SIG_UNBLOCK,&mask,NULL);return;} nobody=0; if((pid=fork())==0) child_replies(); waitpid(pid,0,0);/*necessaria per sincronizzare le uscite a video*/ sigprocmask(SIG_UNBLOCK,&mask,NULL); }
/*****************************************************************************/ /* child_replies(): codice eseguito dal figlio */ /*****************************************************************************/ void child_replies() { struct sockaddr_in nsaddr; int i,s,flag=1; char buf[10];
/*il figlio eredita dal padre il BLOCK della maschera*/ sigprocmask(SIG_UNBLOCK,&mask,NULL); signal(SIGALRM,alrm_child);
if(connection(&nsaddr,&s,msg_temp.host_NS,PORTA_TERM,'D',stderr)) fprintf(stderr,"FIGLIO: errore nella creazione della socket di aquisizione \ dello stato del servizio dal NS %s\n",msg_temp.host_NS);
if(sendto(s,buf,10,0,(struct sockaddr *)&nsaddr,len)<0) fprintf(stderr,"fallito l'invio della richiesta dello stato\n");
alarm(10); if(recvfrom(s,(TUPLA(*)[2])ptr_tab_term,sizeof(TUPLA[2]),0, (struct sockaddr *)&nsaddr,&len)<0) {fprintf(stderr,"%s:fallita la ricezione dello stato inviato dal NS\n", strerror(errno));exit(0);}
alarm(0);
for(i=0;i<2;i++) if((*ptr_tab_term)[i].stato) { fprintf(stderr,"\n\tST in %s:\t porta di servizio %s\n\t\t\t porta di \ updata %s\n\t\t\t porta di resume %s\n\t\t\t porta di KeepAlive %d\n\n", (*ptr_tab_term)[i].host,(*ptr_tab_term)[i].porta_cl, (*ptr_tab_term)[i].porta_ud,(*ptr_tab_term)[i].porta_res, (*ptr_tab_term)[i].porta_ka); flag=0; }
if(flag) fprintf(stderr,"\n\tNESSUN SERVER TELEFONICO REGISTRATO !\n\n\n");
exit(0); }
/**********************************************************************/ void alrm_child() { fprintf(stderr,"\tATTENZIONE: ricezione dello stato fallita !\n"); exit(0); }
void alrm_father() { t_out++;crash=1; } /*********************************************************************/
/*********************************************************************/ /* updata() */ /*********************************************************************/ void updata(int par) { typedef struct { char utente[20]; char telefono[20]; } RECORD;
typedef struct { int len; RECORD (*ptr_tab_data)[]; } MESSAGGIO; MESSAGGIO mes_out,mes_in;
struct hostent *hp; struct sockaddr_in staddr_ud,myaddr; int s,len=sizeof(struct sockaddr_in),num,l,stato=0,z,reclen; char answer;
/*controllo sul numero di ST registrati*/ for(i=0;i<2;i++)if((*ptr_tab_term)[i].stato) stato++; if(!stato) { fprintf(stderr,"\nNON E' POSSIBILE ALCUN AGGIORNAMENTO: servizio non \ disponibile"); fprintf(stderr,"\n\n\t\tpremi invio per ritornare al menů principale..."); getchar();return; } do { do /*controllo sul numero di utenti da INSERIRE/ELIMINARE*/ { clear_screen(); if(par>0) fprintf(stderr,"\n\n\tDigita il numero di untenti da inserire "); else fprintf(stderr,"\n\n\tDigita il numero di untenti da eliminare "); scanf("%d",&mes_out.len);getchar(); } while(!mes_out.len);
mes_out.ptr_tab_data=(RECORD(*)[])malloc(sizeof(RECORD[mes_out.len]));
/*ciclo nel quale vengono inserite le utenze da INSERIRE/ELIMINARE. INSERIMENTO: si richiede UTENTE e n° di TELEFONO. ELIMINAZIONE: si richiede solamente UTENTE ciň significa che tutte le entries corrispondenti all'utente selezionato vengono eliminate senza alcun controllo sui numeri telefonici*/ for(i=0;i<mes_out.len;i++) { fprintf(stderr,"\n\tentry #%d Nome utente ",(i+1)); scanf("%s",(*mes_out.ptr_tab_data)[i].utente);getchar(); if(par>0) { fprintf(stderr,"\t\t telefono "); scanf("%s",(*mes_out.ptr_tab_data)[i].telefono);getchar(); } } if(par>0) /*controllo sulla fase di INSERIMENTO*/ { fprintf(stderr,"\nGli utenti da inserire sono i seguenti:\n"); for(i=0;i<mes_out.len;i++) fprintf(stderr,"\n\tNome utente: %s telefono: %s", (*mes_out.ptr_tab_data)[i].utente, (*mes_out.ptr_tab_data)[i].telefono); } else /*controllo sulla fase di ELIMINAZIONE*/ { fprintf(stderr,"\nGli utenti da eliminare sono i seguenti:\n"); for(i=0;i<mes_out.len;i++) { fprintf(stderr,"\n\t%s",(*mes_out.ptr_tab_data)[i].utente); memset((*mes_out.ptr_tab_data)[i].telefono,0,20); } } fprintf(stderr,"\n\n\n-> 'c' per continuare l' aggiornamento "); fprintf(stderr,"\n-> 'r' per ripetere l'operazione "); fprintf(stderr,"\n-> 'q' per tornare al nemů principale "); fprintf(stderr,"\n\n opzione ");answer=getchar();getchar(); } while((answer!='q')&&(answer!='c')); if(answer=='q') return;
mes_out.len=mes_out.len*par;
/*l'aggirnamento viene effettuato per ogni ST che si č registrato per cui per prima cosa si controlla il campo stato della tabella*/ for(i=0;i<2;i++) { if(!(*ptr_tab_term)[i].stato) continue;
/*assegna la struttura d'indirizzo per la sock ST di comunicazione col ST*/ if(connection(&staddr_ud,&s,(*ptr_tab_term)[i].host, atoi((*ptr_tab_term)[i].porta_ud),'S',stderr)) {extreme();continue;} if(getsockname(s,(struct sockaddr *)&myaddr,&len)==-1) fprintf(stderr,"Errore nella getsockname\n"); fprintf(stderr,"\nConnessione a %s sulla porta %u \n",(*ptr_tab_term)[i].host, ntohs(myaddr.sin_port));
l=sizeof(int)+sizeof(RECORD[abs(mes_out.len)]); if(send(s,&mes_out.len,sizeof(int),0)!=sizeof(int)) {fprintf(stderr,"Errore di TX della dimensione del msg di updata\n"); extreme();continue;} if(send(s,mes_out.ptr_tab_data,sizeof(RECORD[abs(mes_out.len)]),0)!=\ sizeof(RECORD[abs(mes_out.len)])) {fprintf(stderr,"Errore di TX del msg di updata\n");extreme();continue;}
fprintf(stderr,"\n\tla lunghezza del messaggio inviato č %d\n",l); if(recv(s,&mes_in,sizeof(int),0)<1) fprintf(stderr,"Errore in ricezione di aggiornamento avvenuto.\n"); else { mes_in.ptr_tab_data=(RECORD(*)[])malloc(sizeof(RECORD[mes_in.len]));
/*successivamente l'invio si attende un messaggio di risposta che specifichi l'esito dell'aggiornamento*/ reclen=recv(s,mes_in.ptr_tab_data,sizeof(RECORD[mes_in.len]),0); fprintf(stderr,"\ti caratteri letti sono %d\n",reclen); if(par>0) fprintf(stderr,"\tLe entries effettivamente inserite nel db di %s sono \ %d\n",(*ptr_tab_term)[i].host,mes_in.len); else fprintf(stderr,"\tLe entries effettivamente eliminate nel db di %s sono \ %d\n",(*ptr_tab_term)[i].host,mes_in.len);
for(z=0;z<mes_in.len;z++) fprintf(stderr,"\t%s %s\n",(*mes_in.ptr_tab_data)[z].utente, (*mes_in.ptr_tab_data)[z].telefono);
close(s); free(mes_in.ptr_tab_data); } } free(mes_out.ptr_tab_data); fprintf(stderr,"\n\n\t\tpremi invio per ritornare al menů principale..."); getchar(); }
/**************************************************************************/
void extreme() { fprintf(stderr,"\n\nATTENZIONE: non č possibile aggiornare %s\n", (*ptr_tab_term)[i].host); return; }