next   previous   contents

Handling dei segnali

 In questa sezione verra' mostrato come avviene la gestione dei segnali, utilizzati in per la notifica di alcuni eventi e la gestione di situazioni particolari.
 Ciascun evento, infatti, causa l'intervento da parte del kernel, con la conseguente emissione di un particolare tipo di segnale. Quando il processo di servknock riceve certi tipi di segnali anziche' il normale corso di esecuzione del programma, viene eseguita un'apposita routine di gestione degli stessi, detta gestore del segnale o handler.
 Per la precisione i segnali per i quali servknock prevede un handler sono i successivi :

 SIGABRT : il nome deriva da abort. Il segnale indica che il programma stesso ha rilevato un errore, riportato chiamando la funzione abort che genera tale segnale ;
 SIGCHLD : segnale mandato al processo padre quando un figlio termina o viene fermato;
 SIGINT : il nome sta per interrupt, ed indica un segnale di interruzione per il programma. Generato di default dal comando kill o dall'invio sul terminare del carattere di controllo INTR (sequenza di caratteri C-c) .
 SIGQUIT : analogo a SIGINT, con la differenza che utilizza un'altro carattere di controllo , QUIT, corrispondente alal sequenza C-\ .
 SIGTERM : il nome sta per terminate. Segnale generico utilizzato per causare la conclusione di un processo. Diversamente da SIGKILL puo' essere intercettato, ignorato o bloccato. Puo' essere visto come un metodo “educato” per chiedere ad un processo di concludersi.

 Per definire le routines di gestione dei segnali, e' stata utilizzata la funzione signal, il cui compito e' installare un nuovo handler per il segnale indicato dal valore passato come primo parametro. Ciascun segnale e' infatti identificato dal sistema con un numero, ma utilizzare direttamente il suo valore non sarebbe una buona soluzione, poiche' esso potrebbe variare a seconda dall'implementazione del sistema e talvolta dell'architettura hardware.
 Quindi anziche' specificare direttamente questo numero si e' optato per l'utilizzo delle costanti definite in bits/signum.h, che hanno l'indubbio pregio di essere standardizzate e sostanzialmente uniformi tra le diverse implementazioni.
 Il secondo parametro di signal specifica invece la funzione da eseguire quando il segnale viene intercettato.

/* signal handlers */
signal(SIGQUIT, sigexit);
signal(SIGTERM, sigexit);
signal(SIGINT, sigexit);
signal(SIGABRT, sigexit);
signal(SIGCHLD, sigzombie);

 Quando rilevati i segnali SIGQUIT, SIGTERM, SIGINT e SIGABRT, viene eseguita la funzione sigexit, il cui operato si riduce semplicemente alla chiusura del puntatore al fie di log di servknock, del descrittore utilizzato per la libreria libpcap, ed il modulo della libreria libmcrypt caricato nella parte iniziale dal programma.

void sigexit(void)
 {
 if (LogFilePtr)
  {//if
  fprintf(LogFilePtr, "\nServKnock shutdown\t[OK]\n");
  fprintf(LogFilePtr,"\n********\n");
  fclose(LogFilePtr);
  }//endif
 /*close pcap_descriptor*/
 pcap_close(descr);
 /*close mcrypt module*/
 mcrypt_module_close(hd);
 exit(EXIT_SUCCESS);
 }

 Nel caso sia invece intercettato il segnale SIGCHLD, viene invocata la funzione sigzombie .
Tale funzione ha l'obbiettivo di eliminare le istanze relative ai processi figli precedentemente creati, che abbiano ormai terminato la loro esecuzione.
 In seguito ad una fork, infatti, quando il figlio muore o termina correttamente, la sua istanza di processo rimane allocata finche' il padre non se ne prende carico attraverso una chiamata a waitpid. In caso contrario il processo figlio viene mappato come zombie e le sue risorse non liberate; situazione da evitare assolutamente, per non correre il rischio di saturare inutilmente le risorse del sistema.
 La funzione waitpid sospende l'esecuzione del processo corrente, in attesa della conclusione del figlio identificato dal pid specificato come primo parametro. Se il figlio ha gia' terminato la sua esecuzione al momento della chiamata (un processo cosiddetto “zombie”), waitpid ritorna immediatamente, e tutte le risorse assegnate al figlio liberate.
 Come si puo' notare dalle righe di codice riportate, anziche' indicare il pid di uno specifico processo si e' utilizzata la costante WAIT_ANY, che permette di attendere la terminazione di qualsiasi processo figlio. Il terzo parametro e' invece la costante WHOANG, opzione che previene il blocco della funzione quando il processo figlio non e' ancora terminato.
 La funzione ritorna il pid del figlio terminato oppure il valore 0 nel caso venga specificata l'opzione WHOANG e nessun figlio sia disponibile.

void sigzombie(void)
 {
 /*free zombie's resources*/
 while(waitpid(WAIT_ANY, NULL, WNOHANG) > 0)
  ;
 return;
 }


next   previous   contents