Slide riferite alla terza lezione del corso. Trattano dell'utilizzo della shell in generale e dei comandi in essa utilizzabili. Si parlerà anche delle soluzioni ad eventuali problemi di configurazione del sistema ed inoltre delle più comuni tecniche di virtualizzazione ed emulazione o l'utilizzo di wine.
Linux Capabilities: Un miglior root di SUID root.
Traduzione in lingua italiana delle diapositive presentate alla conferenza organizzata dalla Linux Foundation LinuxCon2014, Düsseldorf, 15 ottobre 2014.
Slide riferite alla terza lezione del corso. Trattano dell'utilizzo della shell in generale e dei comandi in essa utilizzabili. Si parlerà anche delle soluzioni ad eventuali problemi di configurazione del sistema ed inoltre delle più comuni tecniche di virtualizzazione ed emulazione o l'utilizzo di wine.
Linux Capabilities: Un miglior root di SUID root.
Traduzione in lingua italiana delle diapositive presentate alla conferenza organizzata dalla Linux Foundation LinuxCon2014, Düsseldorf, 15 ottobre 2014.
Master: Amministratore Linux - Livello Avanzato
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Master: Amministratore Linux - Livello Base
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Videocorso in italiano su Udemy!
https://www.udemy.com/corso-linux-per-sviluppatori-web-lamp-apache-php-mysql/?couponCode=SLIDES10
- Installare un server linux
- Lavorare con la linea di comando
- Gestione gruppi, utenti e permessi
- Bash scripting
- Espressioni regolari
- Apache, NGnix &Https
- Installare PHP & MySql
- Cron e crontab
Il 10 novembre 2015 viene rilasciato TYPO3 CMS 7.6, la nuova versione LTS con supporto fino al 2018. Queste le differenze con la versione 7.5 e fra qualche giorno i documenti con tutte le differenze tra TYPO3 CMS 6.2 LTS e TYPO3 CMS 7 LTS
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...Fulvio Corno
Master: Amministratore Linux - Livello Avanzato
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
La versione 10.1 di TYPO3 è la seconda versione dello sprint per arrivare alla versione LTS (supporto a lungo termine) nel 2020.
La nuova release ingloba più di 240 commit di Git (modifiche del codice sorgente revisionate, testate e approvate) dalla sua versione precedente la 10.0 pubblicata dieci settimane prima.
Sebbene gli utenti di backend non vedranno molti cambiamenti evidenti o nuove funzionalità importanti, TYPO3 versione 10.1 racchiude una serie di miglioramenti nel core.
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolariFulvio Corno
Master: Amministratore Linux - Livello Base
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Una semplice guida che spiega come installare e utilizzare il software open-source Cacti per la gestione della rete.
A simple guide on how to install and use the software open-source Cacti for network management.
Master: Amministratore Linux - Livello Avanzato
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Master: Amministratore Linux - Livello Base
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Videocorso in italiano su Udemy!
https://www.udemy.com/corso-linux-per-sviluppatori-web-lamp-apache-php-mysql/?couponCode=SLIDES10
- Installare un server linux
- Lavorare con la linea di comando
- Gestione gruppi, utenti e permessi
- Bash scripting
- Espressioni regolari
- Apache, NGnix &Https
- Installare PHP & MySql
- Cron e crontab
Il 10 novembre 2015 viene rilasciato TYPO3 CMS 7.6, la nuova versione LTS con supporto fino al 2018. Queste le differenze con la versione 7.5 e fra qualche giorno i documenti con tutte le differenze tra TYPO3 CMS 6.2 LTS e TYPO3 CMS 7 LTS
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...Fulvio Corno
Master: Amministratore Linux - Livello Avanzato
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
La versione 10.1 di TYPO3 è la seconda versione dello sprint per arrivare alla versione LTS (supporto a lungo termine) nel 2020.
La nuova release ingloba più di 240 commit di Git (modifiche del codice sorgente revisionate, testate e approvate) dalla sua versione precedente la 10.0 pubblicata dieci settimane prima.
Sebbene gli utenti di backend non vedranno molti cambiamenti evidenti o nuove funzionalità importanti, TYPO3 versione 10.1 racchiude una serie di miglioramenti nel core.
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolariFulvio Corno
Master: Amministratore Linux - Livello Base
Nel contesto della formazione professionale rivolta ad aziende ed enti pubblici, sono stati preparati ed erogati dei corsi di Amministratore di sistemi Linux, al livello base ed al livello avanzato.
Il contenuto del corso è allineato con alcuni moduli della certificazione LPIC (Linux Professional Institute Certification), a cavallo tra i livelli 1 e 2. Tutto il materiale didattico è disponibile liberamente con licenza Creative Commons BY-NC-SA.
I docenti del corso sono i proff. Giovanni Squillero, Bartolomeo Montrucchio e Fulvio Corno.
Maggiori informazioni: http://elite.polito.it/index.php/teaching/current-courses/255-master-linux-admin
Una semplice guida che spiega come installare e utilizzare il software open-source Cacti per la gestione della rete.
A simple guide on how to install and use the software open-source Cacti for network management.
Project for the class "Advanced Operating System”: we developed a tool for the analysis of Hadoop, DSTAT and HPROF log in order to estimate the performance of a cluster through graphs and warnings.
Used technologies: Java, R, Hadoop, Python, C
More info: http://www.sromano.altervista.org/progetti_magistrale/SOA_HadoopAnalyzerJR.pdf
Apache Maven - Gestione di progetti Java e build automationTiziano Serritella
Apache Maven è un tool per la gestione di progetti e build automation, utilizzato principalmente per progetti Java, il cui obiettivo è: semplificare, uniformare e automatizzare il processo di build di sistemi complessi.
In questa presentazione / guida verranno illustrati i problemi e le criticità dei tool di build automation tradizionali: make e Apache Ant, vedremo poi come installare e configurare Maven, le caratteristiche, gli obiettivi e i punti di forza del tool, le fasi del ciclo di vita, i plugin e i goal, le dipendenze, gli scope e la risoluzione di eventuali conflitti, i repository, i plugin "esterni" e i progetti multi-modulo.
La presentazione è ricca di esempi pratici.
SPRING - MAVEN - REST API (ITA - Luglio 2017)Valerio Radice
Introduzione al framework Java Spring e Maven per realizzare API REST.
Breve introduzione all'uso di Maven per configurare un progetto SpringBoot e realizzare un server REST.
Disponibile il codice dimostrativo su github (link nelle slide, attenzione alle branch).
Valerio Radice (valix85)
Luglio 2017
Back to Basics, webinar 6: Messa in esercizioMongoDB
Questo è l'ultimo webinar della serie Back to Basics
che ti offrirà un'introduzione al database MongoDB. Questo webinar ti guiderà attraverso tutti i passaggi per l'implementazione della produzione.
Il documento si rivolge a chi ha già buone conoscenze relative alle tecniche con cui si realizza un buffer overflow e spiega più in dettaglio come realizzare shellcode e lo shatter attack.
1. UNIVERSITA' DEGLI STUDI DI NAPOLI
FEDERICO II
Progetto di
Laboratorio di Sistemi Operativi
.:Traccia C:.
A.A. 2007/2008
gr.3
Prof. A.Finzi
Vanacore Paolo – 566/1539
2. Indice
1 Contenuto del pacchetto software.............................................2
2 Guida d'uso..................................................................3
2.1 Il server................................................................3
2.1.1 Compilare ed installare il server: due modalità....................3
2.1.2 Compilare ed installare il server: il makefile.....................3
2.1.3 Compilare ed installare il server: lo script bash..................4
2.1.4 Esecuzione del server: esempio d'uso...............................5
2.1.5 Disinstallare il server............................................7
2.1.6 Il file di log....................................................7
2.2 Il client................................................................8
2.2.1 Compilare, installare e disinstallare il client....................8
2.2.2 Esecuzione del client: esempio d'uso ..............................9
3 Il protocollo di comunicazione al “livello software”.........................12
3.1 La “FASE I” del protocollo di comunicazione.............................12
3.2 La “FASE II” del protocollo di comunicazione............................15
4 Considerazioni..............................................................18
4.1 Server: la mutua esclusione.............................................18
4.2 Server: segnali e TSD...................................................19
4.3 Client: una primitiva fuori programma, l'I/O multiplexing................22
4.4 Note: possibili miglioramenti...........................................22
5 Codice sorgente.............................................................24
1
3. 1 Contenuto del pacchetto software
E' di seguito riportato il contenuto del pacchetto software (file e directory)
con una breve descrizione degli elementi che lo compongono:
radice:
client - cartella contenente i files per il client
Documentazione.pdf- la presente documentazione
server - cartella contenente i files per il server
./client:
src - cartella contenente i file sorgente per il client
./client/src:
client.c - file sorgente con funzione main per il client
istruzioni - istruzioni in linea sul gioco
lib - directory delle librerie per il client
Makefile - make file per compilare/installare/disinst. il client
./client/src/lib:
FASI.c - sorgente contenente le funzioni per la gestione delle varie
fasi di comunicazione con il server
FASI.h - header file contenente i prototipi delle funzioni
implementate in FASI.c
socketTools.c - sorgente contenente alcune funzioni per l'I/O su socket
socketTools.h - header file dei prototipi delle funzioni implementate in
socketTools.c
./server:
src - directory contenente i files sorgente per il server
./server/src:
compileMode.sh - script di shell bash per la compilazione del server con
specifica di modalità: “silent” o “verbose”
lib - directoty contenente le librerie usate per il server
Makefile - make file per la compilazione/installazione/disinstallazione
del server
server.c - file sorgente contenente la funzione main del server
./server/src/lib:
clientQueue - directory contenente la definizione di strutture dati e
funzioni per mantenere le informazioni associate ai client e
la gestione di una coda “dei client pronti”
threadStartFunctions – directory contenente le funzioni d'avvio dei threads ed
alcune funzioni accessorie
./server/src/lib/clientQueue:
clientQueue.c - implementazione funzioni per la coda “dei client pronti”
clientQueue.h - dichiarazione funzioni implementate in “clientQueue.c”
./server/src/lib/threadStartFunctions:
socketIOLib - directory contenente i sorgenti per alcune funzioni di I/O su
socket
threadSF.c - file sorgente contenente l'implementazione delle funzioni di
avvio dei threads ed alcune funzioni accessorie
threadSF.h - file header contenente la dichiarazione delle funzioni
implementate in threadSF.c ed alcune macro per le varie
fasi di comunicazione con i client
./server/src/lib/threadStartFunctions/socketIOLib:
socketIOLib.c - file sorgente contenente l'implementazione di alcune funzioni
per l'I/O su socket
socketIOLib.h - header file contenente i prototipi delle funzioni
implementate in socketIOLib.c
2
4. 2 GUIDA D'USO
2.1 Il server
In questa sezione viene analizzata la procedura da seguire per una corretta
compilazione, installazione/disinstallazione ed esecuzione del server
di gioco.
Vengono dapprima trattate le due modalità di compilazione disponibili:
tramite makefile (sez. 2.1.2) e tramite script di shell bash (sez. 2.1.3).
Quindi viene mostrato un esempio d'uso attraverso il quale saranno
analizzati i vari aspetti dell'esecuzione del server (sez. 2.1.4).
Nelle ultime due sottosezioni viene mostrato l'uso del makefile per
disinstallare il server (sez. 2.1.5) e trattato il formato del file di log
sul quale il server annota alcune informazioni durante la sua esecuzione
(sez. 2.1.6).
2.1.1 Compilare ed installare il server: due modalità
Per la compilazione-installazione del server sono stati predisposti
due file al fine di automatizzare tale processo.
La compilazione-installazione del server può pertanto avvenire
scegliendo una delle seguenti alternative:
• Compilazione-installazione tramite makefile1;
• Compilazione-installazione tramite script di shell bash.
Le due alternative differiscono unicamente per la possibilità che
offre lo script bash di impostare la modalità “verbose” o “silent”
del server. L'uso del makefile, invece, comporta la compilazione del
server secondo l'ultima modalità impostata2.
Compilando con specifica della modalità “verbose”, durante la sua
esecuzione, il server mostrerà sullo stdout alcune informazioni circa
la sua attività (sez. 2.1.4), mentre, in modalità “silent”, non verrà
fatto uso di stdout3.
Non vi sono ulteriori differenze tra le due modalità di compilazione.
In entrambi i casi il risultato è una cartella “/server/bin/”
contenente tutto l'occorrente all'esecuzione del server.
2.1.2 Compilare ed installare il server: il makefile
Il processo di compilazione ed installazione tramite makefile consta
di due “classici” comandi: “make” e “make install”.
Il comando “make” esegue la compilazione ed il linking dei sorgenti e
librerie necessarie. Il risultato di tale comando è un insieme di
file oggetto collocati nelle stesse directory dei rispettivi
sorgenti.
Il comando “make install” crea, all'occorrenza, l'albero delle
directory di radice “/server/bin/”, quindi sposta i file oggetto
all'interno di tale albero di directory.
1 Testato con: GNU Make 3.81.
2 Lo script bash modifica opportunamente la definizione di una macro - “VERBOSE” - all'interno dei file sorgente:
“/server/src/server.c” e “/server/src/lib/threadSF.h”. Dopo tale modifica, quindi, viene eseguito automaticamente “make” e “make
install”. Per questo motivo la compilazione “diretta” tramite “make” conserva inalterata la definizione della macro all'ultimo valore
impostato.
3 In entrambi i casi, all'occorrenza di eventuali errori, il server farà uso di stderr.
3
5. Di seguito viene riportato un esempio di compilazione tramite
makefile:
paolo@debian:~/server/src$ ls -l
totale 28
-rwxrwxrwx 1 root root 1714 2008-07-01 21:26 compileMode.sh
drwxrwxrwx 1 root root 0 2008-06-24 05:54 lib
-rwxrwxrwx 1 root root 3575 2008-07-03 17:31 Makefile
-rwxrwxrwx 1 root root 16537 2008-07-01 21:56 server.c
paolo@debian:~/server/src$ make
gcc -c lib/threadStartFunctions/socketIOLib/socketIOLib.c -o
lib/threadStartFunctions/socketIOLib/socketIOLib.o
gcc -c lib/clientQueue/clientQueue.c -o lib/clientQueue/clientQueue.o
gcc -c lib/threadStartFunctions/threadSF.c -o
lib/threadStartFunctions/threadSF.o
gcc -pthread lib/threadStartFunctions/socketIOLib/socketIOLib.o
lib/clientQueue/clientQueue.o lib/threadStartFunctions/threadSF.o
server.c -o server
paolo@debian:~/server/src$ make install
Inizio installazione in: ../bin
Installazione completata.
paolo@debian:~/server/src$
Dalle righe riportate è possibile osservare il processo di
compilazione tramite gcc1 a seguito del comando “make” e le
“informazioni” d'installazione (o meglio “spostamento”) nella
cartella di destinazione (“../bin/”) a seguito del comando “make
install”.
2.1.3 Compilare ed installare il server: lo script bash
Lo script di shell bash realizzato - “/server/src/compileMode.sh” -
automatizza l'intero processo di compilazione ed installazione del
server.
Per avviare la compilazione del server è sufficiente2 eseguire lo
script con uno dei due argomenti: [“verbose”|“silent”].
Si riporta, di seguito, un esempio di compilazione tramite script con
richiesta di modalità “silent” per il server:
paolo@debian:~/server/src$ ls -l
totale 28
-rwxrwxrwx 1 root root 1714 2008-07-01 21:26 compileMode.sh
drwxrwxrwx 1 root root 0 2008-06-24 05:54 lib
-rwxrwxrwx 1 root root 3575 2008-07-03 17:31 Makefile
-rwxrwxrwx 1 root root 16537 2008-07-01 21:56 server.c
paolo@debian:~/server/src$ ./compileMode.sh silent
Compiling in silent mode...
gcc -c lib/threadStartFunctions/socketIOLib/socketIOLib.c -o
lib/threadStartFunctions/socketIOLib/socketIOLib.o
gcc -c lib/clientQueue/clientQueue.c -o lib/clientQueue/clientQueue.o
gcc -c lib/threadStartFunctions/threadSF.c -o
lib/threadStartFunctions/threadSF.o
gcc -pthread lib/threadStartFunctions/socketIOLib/socketIOLib.o
lib/clientQueue/clientQueue.o lib/threadStartFunctions/threadSF.o
server.c -o server
Inizio installazione in: ../bin
1 Testato con gcc (GCC) 4.1.2 20061115.
2 E' sottintesa la necessità di possedere adeguate credenziali per l'esecuzione del file.
4
6. Installazione completata.
paolo@debian:~/server/src$
Come nel caso della compilazione tramite makefile, il risultato
finale del processo di compilazione ed installazione del server è un
albero di directory di radice “/server/bin/” contenente tutto il
necessario all'esecuzione del server.
2.1.4 Esecuzione del server: esempio d'uso
A seguito della procedura di compilazione ed installazione del server
è possibile accedere alla directory “/server/bin/” il cui contenuto è
il seguente:
paolo@debian:~/server/bin$ ls -l
totale 24
drwxr-xr-x 4 paolo paolo 4096 2008-07-02 17:42 lib
-rwxr-xr-x 1 paolo paolo 23890 2008-07-02 17:42 server
Dove:
• la cartella “lib” contiene i files oggetto delle librerie
utilizzate per la compilazione;
• “server” è il file eseguibile per avviare il server di gioco.
A questo punto è possibile avviare il server utilizzando la seguente
sintassi:
./server <port> <timer(seconds)>
Dove i parametri hanno il seguente significato:
1. <port> la porta d'ascolto
2. <timer(seconds)> è il timer1, espresso in secondi, indicante la
durata massima di ogni singola partita.
Ipotizzando di aver eseguito la compilazione del server in modalità
“verbose”2, eseguendo il seguente comando si avvia il server:
paolo@debian:~/server/bin$ ./server 2000 500
Server listening on port:: 2000 - Game timer: 500s
La prima riga di output del server (“Server listening ...”) indica,
come richiesto dalla specifica degli argomenti inseriti
(“./server 2000 500”), che il server è attualmente in ascolto sulla
porta 2000 ed il timer impostato per le partite è di 500 secondi.
Al fine di analizzare alcune delle possibili informazioni che il
server, compilato in modalità “verbose”, invia su stdout, si riporta
una sezione d'esempio:
1 Per conoscere il valore massimo che il timer può as sumere è possibile eseguire il server senza argomenti (“paolo@debian:~/server/bin$
./server”). Nell'ultima riga di output verrà indicato il massimo valore che si può scegliere per il timer ed una sua approssimazione in ore. Il
valore massimo per il timer equivale al massimo intero (con segno – int) rappresentabile sull'architettura che esegue il server, per questo
motivo è un valore che potrebbe variare.
2 Si considera questa ipotesi in quanto la modalità “silent” non prevede alcun output su stdout e quindi ci sar ebbe poco da analizzare.
5
7. paolo@debian:~/server/bin$ ./server 2000 500
Server listening on port:: 2000 - Game timer: 500s
-->* Connection activity:: 127.0.0.1 connected socket descriptor: 5 time event: Wed Jul
2 19:22:53 2008
-><- Client activity:: 127.0.0.1 chosen nick: Paolo
-><- Client activity:: 127.0.0.1 (Paolo) service request: 1 time event: Wed Jul 2
19:22:57 2008
-><- Client activity:: 127.0.0.1 (Paolo) flotta init time event: Wed Jul 2 19:22:58 2008
Details:
4: (0, 0) (1, 0) (2, 0) (3, 0)
3: (0, 1) (1, 1) (2, 1)
3: (0, 2) (1, 2) (2, 2)
2: (0, 3) (1, 3)
2: (0, 4) (1, 4)
2: (0, 5) (1, 5)
1: (0, 6)
1: (0, 7)
1: (0, 8)
-><- Client activity:: 127.0.0.1 (Paolo) service request: 2 time event: Wed Jul 2
19:23:01 2008
-><- Client activity:: 127.0.0.1 (Paolo) service request: 3 time event: Wed Jul 2
19:23:03 2008
-><- Client activity:: 127.0.0.1 (Paolo) service request: 3 time event: Wed Jul 2
19:23:05 2008
-><- Client activity:: 127.0.0.1 (Paolo) service request: 4 time event: Wed Jul 2
19:23:05 2008
<--* Connection activity:: 127.0.0.1 disconnect nick: Paolo time event: Wed Jul 2
19:23:09 2008
Server closing ...
Server close.
paolo@debian:~/server/bin$
Nella prima colonna è presente un simbolo ad indicare la “classe
d'appartenenza” dell'evento occorso, nella seconda colonna viene
specificato il tipo di evento seguito da alcuni dettagli che
differiscono in base all'evento ed infine, nell'ultima colonna, è
presente la data e l'ora in cui è occorso l'evento.
I possibili simboli, tipi di evento e dettagli sono specificati in
tabella 1.
Ovviamente, in caso di server compilato in “silent” mode, non si ha
nessun output su stdout.
Per terminare un server in esecuzione è necessario inviare un segnale
di terminazione (SIGINT: Ctrl+c o SIGQUIT: Ctrl+) al relativo
processo. Si ottiene una corretta chiusura del server anche
attraverso l'invio, al relativo processo, di un segnale di chiusura
del terminale che gestisce il processo stesso (SIGHUP).
simbolo tipo evento Dettagli
-->* connessione di indirizzo ip del client e socket descriptor assegnatogli
un client
-><- attività di un indirizzo ip del client, nick scelto alla connessione, tipo di attività
client effettuata e dettagli eventuali sull'attività eseguita. (es. richiesta
di un servizio al server1, inizializzazione flotta,...)
-<>- interazione indirizzi ip e nick dei client, dettagli circa l'interazione
“tra due (es. inizio/fine di una partita)
client”
<--* disconnessione indirizzo ip del client disconnesso, eventuale nick.
di un client
Tabella 1. Simboli e corrispondenti eventi-dettagli nell'output di un server compilato in “verbose mode”
Come già accennato, durante la sua normale attività, il server
1 Per conoscere la corrispondenza tra il numero che identifica una richiesta ed il tipo di richiesta è possibile visionare la definizione delle
macro con suffisso “_REQ” nell'header file “/server/src/lib/threadStartFunctions/threadSF.h”
6
8. effettua la scrittura di alcuni eventi all'interno di un file di log.
Tale file, se non già esistente, sarà automaticamente creato dal
server al primo avvio (“/server/bin/logfile”) (sez. 2.1.6).
2.1.5 Disinstallare il server
Per “disinstallazione del server” s'intende l'operazione di rimozione
di tutti i file e directory creati a seguito del processo di
installazione. Quindi durante il processo di disinstallazione verrà
rimosso tutto il contenuto della cartella “/server/bin/” (percorso
predefinito di “installazione” definito all'interno del makefile)
compreso l'eventuale file di log (“/server/bin/logfile”).
Il processo di disinstallazione, come riportato nell'esempio a
seguire, si avvia tramite il comando “makefile clean”.
paolo@debian:~/server$ ls -l
totale 12
drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 bin
drwxr-xr-x 2 paolo paolo 4096 2008-06-22 13:46 doc
drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 src
paolo@debian:~/server$ cd src/
paolo@debian:~/server/src$ make clean
Attenzione! tutto il contenuto della cartella ../bin
andrà perso (compreso il file di log)
Premere INVIO per continuare, Ctrl+c per interrompere ...
Pulizia in corso di: ../bin
Pulizia completata.
paolo@debian:~/server/src$ ls -l ../
totale 8
drwxr-xr-x 2 paolo paolo 4096 2008-06-22 13:46 doc
drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 src
2.1.6 Il file di log
Come già accennato, durante la sua esecuzione, il server effettua
alcune operazioni di log su file. Tale file, se non esiste, viene
automaticamente creato dal server e le operazioni future di scrittura
saranno effettuate in append. La posizione del file all'interno del
filesystem1 è la seguente: “/server/bin/logfile”.
Passando ad analizzare il formato delle informazioni contenute in
tale file si ha che:
La prima colonna contiene la data dell'evento mentre nelle successive
colonne vengono specificati i dettagli dell'evento.
I TAG per gli eventi, nella seconda colonna, sono specificati in
tabella 2.
1 Come tutte le notazioni usate finora per la localizzazione di directory/files all'interno del filesystem anche questa volta si è usato un
percorso relativo alla posizione del pacchetto software.
7
9. Tag tipo evento Dettagli
SERVER avvio del porta d'ascolto ("listening port"); timer per le partite ("game
START server timer").
Client connessione di indirizzo ip del client ("ip"); socket descriptor assegnatogli
conn. un client ("c_sfd").
Game inizio partita nicknames dei client ("nick1 VS nick2"); indirizzi ip dei client ("ip1
start tra due client vs ip2").
Game end fine di una nickname dei due giocatori("nick1 VS nick2"); punteggi della partita
partita ("Score"); indirizzi ip dei client ("ip1 vs ip2"); - nel caso di fine
prematura della partita a causa della disconnessione di uno dei player
- l'indirizzo ip ed il nickname del giocatore disconn. ("[ip nick
disconnect]").
Client disconnessione indirizzo ip del client ("ip"); nickname del client ("nick"); socket
disc. di un client descriptor ("c_sfd"); il punteggio al momento della disconnessione
("points"); data/ora di connessione ("since g.sett. mese g.mese
hh:mm:ss anno").
Tabella 2. Tag per le informazioni contenute nel file di log, loro significato e dettagli
2.2 Il client
In questa sezione vengono mostrati i passaggi per compilare, installare e
disinstallare il client oltre ad alcune informazioni circa l'uso del client
in esecuzione.
2.2.1 Compilare, installare e disinstallare il client
Tutte e tre le azioni di compilazione, installazione e
disinstallazione del client avvengono per mezzo dell'uso di un
makefile: “/client/src/Makefile”.
Come per il server, il comando “make” esegue la compilazione ed il
linking “in place” del client, il comando “make install” crea una
cartella “/client/bin/” nella quale posiziona i file oggetto del
client ed infine, il comando “make clean” elimina ricorsivamente la
cartella “/client/bin/” e tutto il suo contenuto.
A scopo illustrativo si riporta un esempio della successione di
comandi sopra descritti:
paolo@debian:~/client$ ls
doc src
paolo@debian:~/client$ cd src/
paolo@debian:~/client/src$ make
gcc -c lib/socketTools.c -o lib/socketTools.o
gcc -c lib/FASI.c -o lib/FASI.o
gcc lib/FASI.o lib/socketTools.o client.c -o client
paolo@debian:~/client/src$ make install
Inizio installazione in: ../bin
Installazione completata.
paolo@debian:~/client/src$ ls ../
bin doc src
paolo@debian:~/client/src$ make clean
Pulizia in corso di: ../bin
Pulizia completata.
paolo@debian:~/client/src$ ls ../
doc src
paolo@debian:~/client/src$
8
10. 2.2.2 Esecuzione del client: esempio d'uso
La sintassi per eseguire il client è la seguente:
./client <ip|serverName> <port>
Dove:
• <ip|serverName> è l'indirizzo ip o l'hostname del server di
gioco al quale si desidera collegarsi.
• <port> è la porta d'ascolto del server di gioco.
Pertanto, è possibile notare che i seguenti due comandi sono
equivalenti:
./client localhost 3000
./client 127.0.0.1 3000
All'avvio del client, se la connessione con il server ha avuto
successo (2-3), viene richiesto l'inserimento di un nickname (5):
1. paolo@debian:~/client/bin$ ./client localhost 2664
2. Connecting to: 127.0.0.1:2664 ...
3. Connected to: 127.0.0.1:2664
4.
5. Inserire nickname:
6. MyNick
Inserito il nick viene mostrato un menù con le varie opzioni
disponibili (identificate da un intero):
_______________________________
1. Your nick: MyNick
2. Your uniq ID: 15
3. Game timer: 300s
4. _______________________________
5. MENU
6. 1.: Imposta la flotta
7. 2.: Mostra players
in attesa avversario
8. 3.: Invisibile (current: ON)
9. 4.: Gioca con player
in attesa
10. 5.: Mostra il campo
11. 6.: Grid (current: OFF)
12. 7.: Istruzioni
13. 8.: ESCI
14. _______________________________
15. Scelta:
In testa al menù (1-3) sono presenti alcune informazioni utili (nick
scelto al momento della connessione, identificativo univoco personale
e timer per le partite). Quindi seguono (6-13) le opzioni
disponibili.
9
11. Il significato delle varie opzioni è il seguente:
– “1.: Imposta la flotta” consente di schierare la flotta sul
proprio campo di battaglia;
– “2.: Mostra players in attesa avversario” consente di visualizzare
i client connessi al server che stanno attendendo un avversario
con cui giocare;
– “3.: Invisibile (current: X)” con X = ON | OFF
se X == “ON” non si verrà mostrati nelle “liste dei players in
attesa” (opz. 2 e 4) degli altri client, con la conseguente
impossibilità di essere scelti come avversari;
se X == “OFF” si è mostrati nelle “liste dei players in attesa”
(opz. 2 e 4) degli altri client, rendendosi così disponibili ad
essere scelti per iniziare una nuova partita.
NOTA: questa opzione è abilitata solo dopo aver schierato la
flotta (opz. 1).
– “4.: Gioca con un player in attesa” mostra la lista dei client in
attesa di un avversario e consente di sceglierne uno per iniziare
una partita;
NOTA: questa opzione è abilitata solo dopo aver schierato la
flotta (opz. 1).
– “5.: Mostra il campo” mostra il campo di battaglia con la propria,
eventuale, flotta;
– “6.: Grid (current: X)” con X = ON | OFF
abilita/disabilita la griglia per la visualizzazione del campo di
battaglia;
– “7.: Istruzioni” mostra alcune informazioni circa il gioco, il
menù e le modalità di inserimento delle navi sul proprio campo;
– “8.: ESCI” termina il programma client.
Si evita di riportare in questo testo ulteriori informazioni circa
l'uso del client che sono comunque visionabili tramite l'opzione 7
del menù di gioco.
Può invece essere utile mostrare l'esempio d'inserimento di una nave.
Supposto che si debba inserire una nave da 4 caselle e che la si
voglia posizionare alle coordinate (D5, D6, D7, D8) come segue:
10
12. - La tua flotta -
A B C D E F G H I J K L M N O P Q R S T
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
0 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 0
1 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1
2 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 2
3 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 3
4 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 4
5 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 5
6 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 6
7 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 7
8 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 8
9 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 9
10 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 10
11 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 11
12 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 12
13 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 13
14 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 14
15 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 15
16 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 16
17 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 17
18 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 18
19 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 19
A B C D E F G H I J K L M N O P Q R S T
E' sufficiente digitare:
“D” come coordinata colonna,
“5” per la coordinata di riga ed
“S” per la direzione.
.:NAVE DA 4:.
Coordinata Colonna (A, B, ..., T): D
Coordinata Riga (0, 1, ...,19): 5
Direzione D (N, S, E, O): S
Ovviamente, in alternativa, è anche possibile digitare:
“D” per la colonna,
“8” per la riga e
“N” per la direzione.
.:NAVE DA 4:.
Coordinata Colonna (A, B, ..., T): D
Coordinata Riga (0, 1, ...,19): 8
Direzione D (N, S, E, O): N
11
13. 3 Il protocollo di comunicazione
al “livello software”
Per come è stata organizzata la gestione dei client e delle partite, dal punto di
vista del server, è possibile scindere due fasi di comunicazione1:
FASE I – “client driven”: periodo di tempo che intercorre tra
l'avvenuta connessione del client e l'inizio di una partita;
FASE II – “server driven”: periodo di tempo tra l'inizio di una
partita tra due client e la fine della stessa.
Queste due fasi di comunicazione si succedono ciclicamente un numero “indefinito”
di volte durante il periodo di connessione continuativa di un client al server2.
Entrambe le fasi sono state realizzate sul concetto sul quale si basa il
paradigma client-server e cioè quello di: “servizio offerto e servizio
richiesto”.
Durante la “FASE I” della comunicazione il client richiede – previa interazione
dell'utente con determinate opzioni del menù di gioco – servizi al server. Per
tale motivo, la prima fase, è stata qualificata come “client driven”.
Nella “FASE II”, qualificata come “server driven”, è il server a richiedere
servizi, o meglio informazioni e cambiamenti di stato, al client.
Nelle successive sottosezioni vengono analizzate le informazioni oggetto di
scambio durante le due fasi di comunicazione.
3.1 La “FASE I” del protocollo di comunicazione
Come precedentemente accennato, in questa fase della comunicazione il
server offre determinati servizi al client che ne richiede.
Ogni servizio è univocamente identificato da un numero intero3.
Le richieste di servizi vengono quindi effettuate dal client e riconosciute
dal server per mezzo dell'invio e ricezione di questi id. interi.
Tenendo presente che inizialmente il server è in attesa di ricevere la
richiesta di un servizio, i servizi offerti durante la prima fase della
comunicazione sono i seguenti:
• SNDFLOTTA_REQ – id. 1:
➢ il client richiede al server di poter
inviare la propria flotta (ciò avviene al termine
dell'immissione delle navi da parte dell'utente
attraverso l'opzione 1 del menù di gioco);
➢ Il server si predispone per la richiesta;
➢ il client invia la flotta;
➢ il server riceve e memorizza, in un opportuno ADT
associato al client, la flotta, quindi attende una
nuova richiesta;
• RCVPLAYERS_REQ – id. 2:
➢ il client richiede la lista dei players online in
1 E' da notare che la struttura dei sorgenti del client (in particolare “/client/src/FASI.h” e “/client/src/FASI.c”) rispecchia “chiaramente” la
suddivisione delle due fasi di comunicazione.
2 Il relativo non determinismo del numero di successioni cicliche delle due fasi di c omunicazione è stato adottato per consentire ad un
client di intraprendere più partite durante una stessa “sessione” di connessione.
3 Ovviamente le associazioni (intero, servizio) all'interno del server equivalgono a quelle definite nel client.
In particolare sono equivalenti le definizioni delle macro riguardanti i servizi di entrambe le fasi di
comunicazione. Tali macro sono definite in “/server/src/lib/threadStartFunctions/threadSF.h” e in
“/client/src/lib/FASI.h”.
12
14. attesa di avversario (quando l'utente sceglie le
opzioni 2 e/o 4 del menù), quindi l'attende.
➢ Il server invia la lista (estraendola da una coda dei
client pronti) e si mette in attesa di una nuova
richiesta di servizio.
➢ Il client legge la lista.
• INVISIBLE_REQ – id. 3:
➢ il client richiede di attivare/disattivare
l'invisibilità (quando l'utente sceglie l'opzione 3
del menù);
➢ il server modifica “lo stato” del client (inserisce o
elimina le info sul client da una coda dei client
pronti) e si mette in attesa di ulteriori richieste;
• STARTGAME_REQ – id. 4:
➢ il client richiede al server di iniziare una partita
con un player in attesa (quando l'utente sceglie
l'opzione 4, dopo un'implicita richiesta del client di
“RCVPLAYERS_REQ”);
➢ il server attende di ricevere l'identificativo (intero
univoco) del giocatore scelto come avversario dal
client;
➢ il client invia l'identificativo dell'avversario
(scelto dall'utente) ed attende una conferma dal
server (0 se il player non esiste o non è disponibile,
1 altrimenti);
➢ il server riceve l'identificativo, verifica se il
client richiesto esiste ed è disponibile (verifica se
è presente in una coda dei client pronti) quindi:
Se il client richiesto è disponibile
invia la conferma (un intero “1”) al
client richiedente
e passa alla FASE II.
Se il client richiesto non è
disponibile avvisa il client
richiedente (inviando l'intero “0”),
quindi attende nuove richieste.
➢ il client riceve la risposta dal server e, nel caso in
cui si tratti di una conferma passa alla FASE II.
Di seguito viene riportato un diagramma di sequenza nel quale si
tiene conto della caratteristica del server di essere concorrente e
multithreads1. Il diagramma illustra un ciclo tipico di servizi
richiesti/offerti tra due client ed un server durante la prima fase
della comunicazione.
1 Ogni thread che gestisce questa fase di comunicazione con il client ad esso assegnato, ha come funzione d'avvio la funzione chiamata
“clientController” definita in “/server/src/lib/threadStartFunctions/threadSF.h”.
13
15. Server
inizializzaz.,
Tempo
socket,
binding,
listening
accept,
allocazione ed
inizializz. ADT
per info client,
ClientA
Connect
listening
client
create
controller
new thread
A
ClientB
login [nickName]
Connect
attesa ricezione
flotta
client create request [1]
controller new thread invio Flotta
B
invio Flotta
attesa
login [nickName] [x, y]* ricezione
lista
request [2]
request [1] lista client
invio Flotta
x1
invio lista
invio Flotta [nick, id]*'^'
[x, y]*
request [3]
invisible switch
request [2] x2
invio lista
[nick, id]*'^' Legenda
attesa ricezione
ID avversario █ Thread
request [4]
___
inizio Partita Attività del server
_ _
Attesa in ricezione
invio ID avv.
___
attesa ricezione Attività “interna”
[int] conferma [0|1]
___
> Invio/Ricezione informazioni
invio Conferma ___
▶ Creazione nuovo thread
[0|1]
x3
14
16. Al fine di analizzare il contenuto della “coda dei client pronti”
(client in attesa di un avversario – opzione 3 [off] del menù) si
sono individuati tre istanti di tempo: x1, x2 ed x3.
All'istante t=x1 la coda dei client pronti risulta essere vuota, in
quanto, dall'avvio del server, nessun client ha effettuato una
richiesta [3]:
*clientReadyQueue null
All'istante t=x2, a seguito di una richiesta [3] da parte del client
A la coda dei client pronti contiene un unico elemento che punta ad
un ADT associato al client stesso:
*clientReadyQueue info
Client A
All'istante t=x3, se l'identificativo dell'avversario scelto dal
client B (a seguito della richiesta [4]) corrisponde
all'identificativo del client A, allora, quest'ultimo sarà rimosso
dalla coda dei client pronti ed il thread clientController B invierà
un intero “1” al client B. A questo punto si passa alla “Fase II”
della comunicazione. In caso contrario il server invierà un intero
“0” al client B e resterà in attesa di ulteriori richieste.
E' da notare che, a seguito di una richiesta [3] da parte di un
client che ne comporta lo stato di “visibilità”1, il client stesso è
ancora abilitato ad effettuare richieste al server. In questo caso,
però, qualunque richiesta di servizio, diversa dalla [3], che il
client effettui, viene preceduta da un'implicita2 richiesta [3] che lo
rende “invisibile” (viene estratto dalla coda), quindi viene
espletato il servizio richiesto ed infine si ha un'ulteriore
implicita richiesta [3] atta a rendere nuovamente “visibile”
(inserito in coda) il client.
3.2 La “FASE II” del protocollo di comunicazione
In questa sezione sarà analizzata la seconda fase del protocollo di
comunicazione che consiste nell'insieme delle possibili informazioni
scambiate tra due client ed il server nel periodo di tempo intercorrente
l'inizio di una partita e la fine della stessa. Tale fase viene definita
“server driven” in quanto i client ricevono richieste di informazioni dal
server che quindi “guida” la comunicazione.
Come per la prima, anche per la seconda fase di comunicazione, sono stati
definiti alcuni identificativi interi3 ad indicare le informazioni richieste
dal server.
Il server è, in questo periodo di tempo, rappresentato da un thread4
“chiamato playController” che gestisce la partita tra i due client.
Inizialmente entrambi i client sono in attesa di ricevere richieste.
Le possibili informazioni richieste dal server sono le seguenti:
1 Cioè quando la richiesta comporta l'inserimento delle informazioni sul client all'interno della co dei client pronti, come avviene nel
da
diagramma di sequenza precedente per il Client A dopo l'istante di tempo t=x2.
2 Viene usato il termine “richiesta implicita” in quanto questo tipo di richiesta viene inviata dal client senza interazione con l'utente.
3 Nel client la definizione delle macro si trova nel file header: “/client/src/FASI.h”. Mentre per il server esse si trovano
in:”/server/src/lib/threadStartFunctions/threadSF .h”.
4 La cui funzione d'avvio, definita in ”/server/src/lib/threadStartFunctions/threadSF .h”, è stata nominata: “playController”.
15
17. • SHOOTCOORD_REQ – id. 1:
➢ il server invia la richiesta al clientA (client “di
turno”) ed attende l'invio di una coppia di coordinate
rappresentanti uno “sparo”;
➢ il clientA invia una coppia di interi (coordinate sparo
lette da stdin);
➢ il server, riceve le coordinate, verifica se esse hanno
colpito/affondato una nave del clientB1 calcolando un
responso.
• SNDSHTRESP_REQ – id. 2:
➢ il server richiede al clientA (client “di turno”) di
poter inviare il responso in seguito ad un suo “sparo”
(calcolato al termine della fase avviata da una richiesta
di SHOOTCOORD_REQ);
➢ il client attende il responso riguardante il suo ultimo
sparo effettuato;
➢ il server invia il responso al client;
➢ il client riceve il responso ed attende ulteriori
richieste.
• SNDADSCORE_REQ – id. 3:
➢ il server richiede al clientB di poter inviare le
coordinate ed il punteggio dell'ultimo tiro del clientA;
➢ il client attende le coordinate del tiro dell'avversario
ed il suo punteggio;
➢ il server invia coordinate e punti al clientB;
➢ il client riceve coordinate e punti, quindi attende
ulteriori richieste.
• ENDGAME_REQ – id. 4:
➢ il server invia una “richiesta” (avviso) di fine partita;
➢ il client destinatario dell'avviso attende di ricevere il
“responso partita”;
➢ il server invia il “responso partita”, quindi passa alla
FASE I (crea un thread clientController per gestire la
comunicazione con il client);
➢ il client riceve l'informazione, quindi, passa alla FASE
I.
Oltre alla definizione degli identificativi numerici sopra riportati, per
questa fase di comunicazione, sono stati definiti anche i seguenti:
• COLPITA_RESP – id. 1;
AFFONDATA_RESP – id. 2;
ACQUA_RESP – id. 3: identificano i tre possibili responsi
di uno “sparo”. Sono inviati a seguito
di una richiesta accordata di
SNDSHTRESP_REQ ed, insieme alle
coordinate del tiro, una richiesta di
SNDADSCORE_REQ.
1 Questa verifica viene effettuata su di un'opportuna struttura dati mantenuta dal server per le infor
mazioni dei client. E' possibile
visionare tale struttura nel file: “/server/src/lib/clientQueue/clientQueue.h”
16
18. • WIN_RESP – id. 1;
LOSS_RESP – id. 2;
PLAYER_DISCONN – id. 3;
EQUALS_RESP – id. 4: identificano il “responso di una
partita”. Nell'ordine, partita vinta,
persa, avversario disconnesso e
partita patta.
Si riporta di seguito un diagramma di sequenza atto a mostrare le
informazioni scambiate tra il server (un thread “playController”) e due
client: clientA e clientB. Inizialmente s'ipotizza che il turno di “sparo”
sia del clientA.
play
ClientB controller ClientA
acquisizione
coordinate
request [1] sparo da
richiesta coordinate sparo stdin
calcolo
responso tiro
invio coordinate sparo
[x, y] (2*int)
request [2]
richiesta invio responso tiro
attesa
responso tiro
invio responso tiro
(1*int)
attesa
responso tiro request [3]
avversario
richiesta invio coord.-
tiro e punti avv.
invio coord.-punti
tiro avv.
[x, y, z] (3*int) Legenda
█ Thread
_ _
Attesa in ricezione
___
Attività “interna”
___
> Invio/Ricezione informazioni
La fase rappresentata nel diagramma di sequenza si ripete ciclicamente e,
ad ogni iterazione, i client vengono “scambiati di ruolo”. Si prosegue fin
quando uno dei due player ha affondato tutte le navi dell'avversario, un
client si disconnette oppure alla scadenza del timer di gioco1.
1 La gestione della fine di una partita, per scadenza timer viene mostrata nella sezione 4.2.
17
19. 4 Considerazioni
L'applicativo realizzato può essere considerato in versione “alpha” in cui
è definita la struttura logica di base scelta al fine di rispettare le
specifiche richieste. Sicuramente si possono apportare diverse modifiche ed
aggiunte interessanti al progetto. Nell'ultima sezione ne vengono annotate
alcune.
Nelle sottosezioni che seguono vengono analizzati alcuni aspetti ritenuti
di maggior interesse nei quali si mostra l'uso che si è fatto di alcune
primitive che si sono rivelate fondamentali durante la “progettazione
concettuale” e la stesura del codice. Al fine di rendere il presente testo
il meno prolisso possibile si evita di riportare alcuni aspetti,
altrettanto importanti, per i quali è comunque possibile visionare la
documentazione interna.
4.1 Server: la mutua esclusione
La gestione della comunicazione con ogni client è basata sulla gestione e
manipolazione di alcune informazioni ad essi associate1. Come visto in
sezione 3, tali informazioni vengono dapprima (durante la “FASE I”, sez.
3.1) manipolate da un thread la cui funzione d'avvio è chiamata
“clientController”, ed in un secondo momento (“FASE II”, sez. 3.2) passano
sotto la gestione di un thread “playController”.
Quando un client imposta la visibilità, la struttura dati contenente le sue
informazioni viene inserita all'interno di una coda dei client pronti2.
Per ogni processo server in esecuzione esiste un'unica coda dei client
pronti alla quale più thread possono accedervi in maniera concorrente. Per
questo motivo è stato associato alla coda un mutex3 atto a regolamentare le
operazioni di I/O sulla coda. A tale scopo è stata definita4 la seguente
struttura dati:
struct mutexQueue{
struct list *queue; //>Pointer alla coda
pthread_mutex_t *mutex; //>Mutua esclusione
};
Un esempio di operazione che tiene conto dell'accesso concorrente alla coda
è il seguente:
/*! ENTRY SECTION !*/ //>Chiude il mutex associato alla coda
if (pthread_mutex_lock(clientReadyMutexQueue->mutex))
perror("mutex_lock"), exit(1);
/*! SEZIONE CRITICA !*/ //>Elimina dalla coda il client
clientReadyMutexQueue->queue = removeElementByKey(
clientReadyMutexQueue->queue,
infoClient->c_sfd,
&infoClientTmp);
if (infoClientTmp == NULL) //>Se il client non era in coda lo inserisce
clientReadyMutexQueue->queue = insertInHead(
clientReadyMutexQueue->queue,
infoClient);
1 Per la struttura dati che mantiene queste informazioni si veda la definizione della “struct clientData” in
“/server/src/lib/clientQueue/clientQueue.h”.
2 La definizione della coda (linked list) e le funzioni accessorie per la sua gestione sono definite all'interno dell'header file
“/server/src/lib/clientQueue/clientQueue.h”.
3 Questo non è l'unico caso in cui si fa uso diun mutex, ma lo si è scelto in quanto ritenuto di maggior interesse.
4 La definizione è collocata in “/server/src/lib/threadStartFunctions/threadSF .h”.
18
20. /*! FINE SEZIONE CRITICA !*/
/*! EXIT SECTION !*/ //>Apre il mutex associato alla coda
if (pthread_mutex_unlock(clientReadyMutexQueue->mutex)
perror("mutex_unlock"), exit(1);
L'esempio mostra le istruzioni che ogni thread “clientController” esegue in
seguito ad ogni ricezione di richiesta INVISIBLE_REQ.
Si può generalizzare in pseudo-codice la struttura di ogni segmento di
codice che accede alla coda per operazioni di I/O nel seguente modo:
blocca_mutex(clientReadyQueue->mutex) //>Entry section (attesa passiva)
... esegui I/O sulla coda ... //>Sezione critica
sblocca_mutex(clientReadyQueue->mutex) //>Exit section
4.2 Server: segnali e TSD
Anche i segnali hanno avuto un ruolo fondamentale nello sviluppo del
server. Si è fatto uso dei segnali sia per un'adeguata gestione della
terminazione del server, sia per la gestione del timer delle partite.
Per “adeguata gestione della terminazione del server” s'intende un insieme
di operazioni da effettuare ad ogni chiusura. In particolare, l'operazione
fondamentale che viene eseguita è quella di annotare sul file di log (sez.
2.1.6) l'evento di chiusura del server accompagnato dalla data ed ora
dell'istante in cui quest'ultima è avvenuta.
Poiché il server, come da specifiche richieste, non riceve input da stdin,
si è scelto di affidare il processo di terminazione ai seguenti segnali:
• SIGINT (interruzione da terminale: “Ctrl+c”);
• SIGQUIT (interruzione da terminale: “Ctrl+”);
• SIGHUP (chiusura del terminale che gestiva il processo).
Nella fase di inizializzazione del server, al suo avvio (main in
“server/src/server.c”), viene registrato un gestore per i segnali sopra
riportati:
if (signal(SIGINT, sig_hand) == SIG_ERR) //>Ctrl+c (interr. da terminale)
perror("signal"), exit(1);
if (signal(SIGQUIT, sig_hand) == SIG_ERR) //>Ctrl+ (interr. da terminale)
perror("signal"), exit(1);
if (signal(SIGHUP, sig_hand) == SIG_ERR) //>Terminale del proc. chiuso
perror("signal"), exit(1);
Il gestore ha il seguente corpo:
static void sig_hand(int signo){
#if VERBOSE
printf("Server closing ...n");
#endif
exit(0); //>Esegue exit_log
}
19
21. Avendo preventivamente registrato un exit handler che effettua le
operazioni di log su file, si ottiene il risultato che, all'occorrenza dei
segnali sopra riportati, prima della terminazione del server, viene
effettuato il log.
Si riportano di seguito due frammenti di codice riguardanti la
registrazione dell'exit handler ed il corpo della funzione registrata:
...
if (atexit(exit_log) != 0) //>Registrazione Exit handler
perror("atexit(exit_log"), exit(1);
...
...
static void exit_log(void){
char buffer[MAX_BUFFER];
getTime(buffer); //>Data/ora chiusura server
strcat(buffer, "tSERVER CLOSEnn"); //>Intestazione
logging(buffer); //>Log su file
#if VERBOSE
printf("Server close.n");
#endif
}
...
Per quanto riguarda la gestione del timer delle partite si è fatto uso del
segnale SIGUSR1.
Si consideri il seguente scenario esplicativo:
– un “clientA” è nello stato “visibile” (le informazioni del clientA sono
presenti nella coda dei client pronti);
– un “clientB” effettua una richiesta STARTGAME_REQ al server seguita
dall'id del clientA (richiesta di iniziare la partita con il “clientA”).
– sia “clientControllerA” il thread che gestisce la “FASE I” della
comunicazione con il “clientA”;
– sia “clientControllerB” il thread che gestisce la “FASE I” della
comunicazione con il “clientB”.
Al momento della ricezione della richiesta STARTGAME_REQ e dell'id del
clientA, il thread “clientControllerB” estrae dalla coda dei client pronti
le informazioni del clientA1. Quindi, leggendo della struttura dati del
clientA il tid del “clientControllerA”, lo termina:
...
static struct clientData *estraiClient_StopThred(int i){
struct clientData *infoClientTmp = NULL;
/*! ENTRY SECTION !*/
if (pthread_mutex_lock(clientReadyMutexQueue->mutex))
//>Chiude il mutex associato alla coda
perror("mutex_lock"), exit(1);
/*! SEZIONE CRITICA !*/
//>Se esiste un client con ID i lo rimuove dalla coda e termina i lthread
clientReadyMutexQueue->queue = removeElementByKey(
clientReadyMutexQueue->queue,
i, &infoClientTmp);
if (infoClientTmp != NULL)
pthread_cancel(infoClientTmp->ctrlTid);
/*! FINE SEZIONE CRITICA !*/
/*! EXIT SECTION !*/
//>Apre il mutex associato alla coda
1 Si suppone che al momento in cui il clientControllerB accede alla coda dei client pronti il clientA sia ancora pr
esente in essa.
20
22. if (pthread_mutex_unlock(clientReadyMutexQueue->mutex))
perror("mutex_unlock"), exit(1);
return (infoClientTmp);
}
La terminazione del “clientControllerA” viene effettuata all'interno della
stessa sezione critica nella quale si esegue l'estrazione dalla coda del
clientA per evitare “incongruenze” dovute alla possibilità che il clientA
ha di modificare il suo stato di “visibilità”.
Dopo aver inviato la conferma al “clientB”, il “clientControllerB” avvia un
thread (“playController”) per gestire la “FASE II” della comunicazione.
Dopo la creazione del thread, il “clientControllerB” attende un numero di
secondi pari al timer impostato, quindi, invia un segnale SIGUSR1 al thread
“playController” creato.
In caso di terminazione della partita prima dello scadere del timer, il
thread “playController” termina “clientControllerB”.
Di seguito si riportano due frammenti di codice relativi al
“clientController” e alla funzione registrata (in “/server/src/server.c”)
per il segnale SIGUSR1:
...in clientController:
...
//>Crea nuovo thread per gestire la partita tra i due client
pthread_create(&i, NULL, playController, players);
pthread_detach(i); //>Non interessa valore d'uscita del thread (distaccamento thread)
sleep(timer); //>Attende timer secondi
pthread_kill(i, SIGUSR1); //>Invia il segnale sigusr1 al thread che gestisce la partita
...
...gestore per SIGUSR1:
void timeOut(int signo){
if (signo == SIGUSR1){
//>Assegnazione puntatore alla TSD
int *stopGameP = (int *) pthread_getspecific(stopGameKey);
//>Aggiornamento valore
*stopGameP = 1;
}
}
...
Come si può osservare dal codice sopra riportato, il gestore di segnali
imposta il valore di un ThreadSpecificData (di key: “stopGameKey”) ad “1”.
Prima della richiesta di ogni servizio, il “playController” effettua un
test sul valore del TSD al fine di verificare se il timer per la partita è
scaduto:
...in playController:
if (*stopGameP){ //>Se è impostata la flag di fine partita
if (request(player1->c_sfd, ENDGAME_REQ)){ //>Richiesta servizio player1: fine partita
if (request(player2->c_sfd, ENDGAME_REQ)){
freeAndExit(player1, 0);
freeAndExit(player2, 1);
}
freeAndRestart(player1, player2, tid);
}
request(player2->c_sfd, ENDGAME_REQ); //>Richiesta servizio player2: fine partita
restart(player1, player2); //>Avvia due threads per gestire la connessione con i client
}
...
21
23. 4.3 Client: una primitiva fuori programma, l'I/O multiplexing
Durante la fase di progettazione dell'applicazione è nata la necessità di
poter controllare la disponibilità di informazioni su due file descriptor
contemporaneamente.
Tale necessità si è posta quando è stata affrontata la gestione, lato
client, della “visibilità” (sez. 3.1). Inizialmente si era deciso di non
consentire ai client la richiesta di servizi durante questo periodo di
tempo ma, una tale “soluzione” avrebbe comportato l'impossibilità per il
client stesso di “cambiare idea”. In poche parole non sarebbe stato
possibile il passaggio da “visibilità” ad “invisibilità” (con tutto ciò che
questo ne comporta1).
Dare la possibilità al client di attendere un avversario e
contemporaneamente poter richiedere servizi al server si traduce nella
necessità di poter controllare, contemporaneamente, in lettura il file
descriptor STDIN_FILENO (per le richieste di servizi dell'utente) ed il
socket file descriptor sul quale si svolge la comunicazione con il server.
Una possibile soluzione sarebbe stata quella di adottare la tecnica del
polling aprendo i due descrittori in modalità O_NONBLOCK. Tale soluzione,
oltre ad influenzare tutte le altre operazioni di I/O che sono state
strutturate per descrittori aperti in modalità bloccante, è comunemente
ricordata per la sua inefficienza: gran parte dei cicli di CPU sono
inutilmente impegnati per system call che spesso falliscono (dati non
disponibili).
La scelta è quindi caduta sull'I/O multiplexing che consente di controllare
più file descriptor contemporaneamente, di bloccare il processo (attesa
passiva) se non è possibile effettuare le operazioni richieste e di
riprendere l'esecuzione quando è possibile effettuare almeno una delle
operazioni richieste.
Di seguito viene riportato un frammento di codice che si riferisce alla
situazione appena descritta:
...in waitPlayer() - FASI.c:
...
//>Aggiunge il socket descriptor all'insieme dei socket da controllare in lettura
FD_SET(sfd, &rfdset);
//>Aggiunge lo stdin descriptor all'insieme
FD_SET(STDIN_FILENO, &rfdset);
//>Aspetta per operazioni di lettura
select(maxfd, &rfdset, NULL, NULL, NULL);
//>Pronto a leggere da stdin
if (FD_ISSET(STDIN_FILENO, &rfdset)){
... operazioni di lettura da stdin e gestione richieste servizi ...
}
//>Pronto a leggere da sfd
if (FD_ISSET(sfd, &rfdset)){
... operazioni di lettura da socket descriptor ...
}
...
4.4 Note: possibili miglioramenti
In questa sezione vengono annotate alcune possibili modifiche al fine di
migliorare le caratteristiche del pacchetto software realizzato.
(1) In riferimento alla sez. 3.1:
sollevare il client dalla responsabilità di inviare richieste
1 Questa limitazione avrebbe impedito qualunque richiesta da parte del client.
22
24. implicite di INVISIBLE_REQ quando si trova nello stato di
"visibilità" e richiede servizi al server.
Possibile soluzione:
aggiungere alla struttura dati che il server mantiene per ogni
client una variabile “flag” che codifica gli stati di
“visibilità”/”invisibilità”.
In questo modo si può anche scegliere di mantenere in coda
tutti i client collegati riconoscendo quelli in attesa di
avversario (“visibili”) dal valore della flag.
(2) In riferimento alla sez. 4.1:
ridefinire la coda dei client pronti, della libreria
“/server/src/lib/clientQueue/clientQueue.h”, in maniera che
le funzioni definite per la sua gestione prevedano l'accesso
in mutua esclusione.
Possibile soluzione:
portare la definizione del mutex associato alla coda
all'interno della definizione della coda stessa.
Dotare le funzioni per la manipolazione della coda
di una “entry section”, “sezione critica” ed “exit section”.
Aggiungere una funzione di creazione di una nuova coda
contenente tutte le istruzioni di allocazione necessarie.
(3) Imporre un limite di tempo massimo per la scelta delle coordinate
di sparo per l'utente “di turno”.
Possibile soluzione:
lo scopo è “facilmente” raggiungibile tramite l'uso del segnale
SIGALRM.
(4) Consentire ad un utente di ritornare al menu principale durante una
partita. Probabilmente una possibile soluzione richiederebbe l'uso
dell'I/O multiplexing o del polling.
(5) Mostrare agli utenti lo scorrere del timer della partita e del timer
relativo definito al punto (3).
Possibile soluzione:
creare due thread che, in maniera concorrente ed in mutua
esclusione, “ogni secondo”, scrivono i valori dei timer su
stdout.
(6) In riferimento alla sez. 4.2:
eliminare il TSD stopGameKey (flag per fine timer) e rendere
"coppiaInfoClient" TDS in modo che il gestore del segnale
SIGUSR1 invii lui stesso le richieste ai due client di fine
partita ed avvii due thread "clientController" per gestirli.
(7)In riferimento alla gestione della richiesta di RCVPLAYERS_REQ
(sez.3.1) modificare la funzione “inviaClientPronti” definita in
“/server/src/lib/threadStartFunctions/threadSF.h” in modo che la
chiamata “bloccante” di scrittura sul socket descriptor sia posta
all'esterno della sezione critica.
23
25. 5 Codice sorgente
./client/src:
client.c - file sorgente con funzione main per il client
Makefile - make file per compilare/installare/disinst. il client
./client/src/lib:
FASI.c - sorgente contenente le funzioni per la gestione delle varie
fasi di comunicazione con il server
FASI.h - header file contenente i prototipi delle funzioni
implementate in FASI.c
socketTools.c - sorgente contenente alcune funzioni per l'I/O su socket
socketTools.h - header file dei prototipi delle funzioni implementate in
socketTools.c
./server/src:
compileMode.sh - script di shell bash per la compilazione del server con
specifica di modalità: “silent” o “verbose”
Makefile - make file per la compilazione/installazione/disinstallazione
del server
server.c - file sorgente contenente la funzione main del server
./server/src/lib/clientQueue:
clientQueue.c - implementazione funzioni per la coda “dei client pronti”
clientQueue.h - dichiarazione funzioni implementate in “clientQueue.c”
./server/src/lib/threadStartFunctions:
threadSF.c - file sorgente contenente l'implementazione delle funzioni di
avvio dei threads ed alcune funzioni accessorie
threadSF.h - file header contenente la dichiarazione delle funzioni
implementate in threadSF.c ed alcune macro per le varie
fasi di comunicazione con i client
./server/src/lib/threadStartFunctions/socketIOLib:
socketIOLib.c - file sorgente contenente l'implementazione di alcune funzioni
per l'I/O su socket
socketIOLib.h - header file contenente i prototipi delle funzioni
implementate in socketIOLib.c
24
26. c Indice Codice Sorgente
es
tne
cc/l m
ni/e
.lr
.vbe/
niaio :
n/lgtp
Ccalta/ei T/
TNa/lh/l E
Ptaaoo/f /* K
mcenr )ECE(ss
arkoC 0RONtC
neci> ,S,Fcd
c sa/ TS_ks
eotee ;AKTAof
kpoz/ M_Ie=
nP
)ien ;E0ne
i
ail Ln(m
n"u e ((
g
ele/ ENke
e
imc" )M,t
a i _*O
lns> NA(e
lli/ x,im cS
p
ora>l/_;tl"s
ctr(e n)Ir
caai _ar
lea/t 1,goi
iNrrR t"sr
ndhig G)xIoi
aeiaC ( ra
mdec/ i ig
ono e
Int>R=aeGnf
(d+/E=h,Si
)sdts/)I)*Tla
ir.zr RSdi,tr
/diVv/ [a_cu
‘Tsae ;sdjt
‘Es/S gad,i
‘irr> rnat
‘lre/ diki
*ibdr v_gsn dN;ti
c
is
/‘ {rhr(t
‘‘ ]rcnm
‘
‘
*‘
‘/ )acann
mN‘‘‘‘‘(‘‘‘‘‘
a‘‘‘‘‘><‘‘‘‘‘
n‘‘‘‘‘)‘‘‘‘‘/
c‘‘‘‘‘ ‘‘‘‘‘
>‘‘
e‘‘‘‘‘‘A‘‘‘‘‘
k‘‘‘‘‘N‘‘‘‘‘
i‘‘‘‘‘
r‘‘‘‘‘‘IN i *
o‘‘‘‘‘‘ME
r‘‘‘
c e/
e/
eS
t‘fo‘‘ _
pd‘‘‘‘ E
i/t>‘ eesNm
g;nce
ae
t‘‘‘‘h
a‘‘‘‘‘‘
iesovv‘
a‘‘‘‘‘‘
s]Mai
A‘‘‘‘‘‘‘‘
hnaia
ieoka i
gne
i‘‘‘‘‘‘
iodc
b‘e
i‘
bn
‘‘l‘‘‘‘‘‘l‘l‘
‘sicSin‘lgfNN
‘‘‘‘‘‘‘o‘AnE
‘‘‘"‘‘‘l‘‘rT
‘‘‘‘":‘‘‘l‘O
‘‘‘.‘‘‘‘‘‘t *
‘kInrdt‘;‘*
‘Feu‘uns *
h‘‘‘‘‘‘‘‘*
‘ tcoL[r
/‘‘‘‘‘‘‘‘‘‘‘‘ n‘‘l‘_:*
n‘‘
t‘
gii‘‘
‘‘ ‘tae*
‘
‘‘
‘‘ onhv*
*‘‘‘ ‘sdira
‘‘‘‘‘‘‘‘‘‘‘‘ls
‘‘‘‘‘‘‘‘‘‘‘‘‘
‘‘‘‘‘‘‘‘‘‘‘‘‘
‘‘‘‘‘‘‘‘‘(‘‘‘
‘‘‘‘‘‘‘;‘‘‘‘‘
‘‘‘‘‘‘‘)‘‘‘‘‘ i‘‘‘/
‘x
gdi
pa
necet
soH
ar‘*
iit
r‘‘‘‘‘‘‘‘l‘‘<
‘6 n‘‘‘‘‘‘‘‘d/
t‘‘‘‘‘‘‘‘‘‘‘(
/o‘‘‘‘‘‘‘‘‘‘‘*
;‘‘‘‘‘‘‘‘‘‘‘n
‘*tp [ >
)‘‘‘‘‘‘‘‘‘‘‘2
‘‘i
‘t_
‘_
*p1,__‘e ) a
vhor e
sspp
eag‘ie
eev
ztivgcnies ips
ggrri‘cn
m,zlcn
o‘aoaa
iz*tarrat‘vt
d‘ivr‘t‘odia‘"goI
edpeni*
ai3,acdtni*
ze‘eitr‘c
‘‘‘‘‘‘]‘‘‘‘‘‘s
‘‘‘‘‘‘‘‘‘‘‘‘‘
‘‘‘‘‘‘‘r‘l‘‘‘
‘‘‘‘‘‘‘l‘‘"‘‘
‘‘‘‘‘‘r‘r(‘‘‘
‘‘‘‘‘‘‘‘‘‘r‘‘
tuin‘*ea‘af*eeSs
a2ut‘‘‘‘it oi
eir
tar i
/‘‘‘‘‘‘‘l‘‘l>/
‘‘‘l‘‘irgzres
‘‘‘‘‘‘‘‘l'"‘e
‘:‘‘‘‘‘‘‘l‘‘V
‘‘‘‘‘‘‘‘‘‘‘‘<
‘‘‘‘‘(‘‘‘"‘‘*
‘‘idrnvd‘ccI
*‘ain)‘‘‘‘‘‘r
o‘‘"lsi/ ‘)
g‘rcecz *
s)e
aao
o‘‘ltpn (
c‘‘iisn/ b1
ifvian
deeg F
i>a
i‘ileeo
noriuio‘‘‘
oranFpr‘‘‘
usnz/oS‘‘
eno> A‘#
treiut(‘‘
somP .<n
i"ro>iP‘‘*
mce bd#
ai d /
d/ /
leir t<ln t
.. /e ecu
.. d >yl
.t r m/ ssd#/ >eu
/ hnc
."c
> .nd#
i "Fei<n
hfl
lei
/ Iiu
> htei
psl
<cc
n
_ _ee ./u
..esr >ye
naIF i
ennaio
ia/d
o)nyli/ n
ntne a
aeoOlP htd
axia
pyl
n
oetOi l
rt,zih/ #
iuri <c
i)a> u
/e))tbIn/ >dd#
nonrnfdt .<c
iioiorrS .sl
nd
sh.,pr(a/ htu
otirrnzS bei
dsdr(ba> iei
erdz.d/ i
moitdn l
aiiizn d
f//
io
lnvl,u_t >sl
(.f(nsn/ o n
co> h<c
tic >gd
ndG .nl
gd/ e n
or/ ad
ei/ / n
st/ en
knG /yu
i.t/ isd#
aee kiu
est htu
l,s etd
cro >tsl
cs nnei
.ee .nei
no>hl<c
1,tncii,l>>csl/
tns .s8i
elk/ho<c
ii/ tie# 7
0#
0/
2
6
27. c Indice Codice Sorgente
e
cc/Nim
ni/e
esia
tnl/l
.lr zb
ataaoo/f [
rogtp /l
pvae:
nzo
tcalta/ei v
oia/lh/
oai/ 2dn
esi> ras
rtep )rnl
rho/ vdi
( g>
)_zia ziat}
dotI [rb=
sio )itho
;enzt_ zaooe
int ;n/tr
[r tgtap
)uzf0lrl1(iti
)btfme>ei>up}
r(lurnvd],(i
ef,bsdr;;((s
fodofe)rane
fee]loodeon
r,i s]pN=t ii_
/
_**
_ee
xèeedr(t
mozR1rnuLDufh
amdl]aytzr=ii
nom/r.beth=b
_rrnrrtgr[(s
ai>r"beui((
eonvet]l6oa
a;vma(sN=/
nrle1(l)rLer
een/ >
mdtu),nhrirnf
eiio)easEDEfi
eeof;gvooh.rs gdLs_
td²sr'[n
__np)fpe
a_Rhfuc
a,S²r_
eafNRofa
eafti
hhiy_non
[m;TTer
z'e /
looirds"eUan
do/iesnoto_
ngosodiAI_
onul()yto)rrs
inlzind h
nesèeai*Lse
0r)tco
[o>otf
vh/srp
]iL)[ai
<5]rl
["a0evh
o0r<xn
pa{](i
mo1;i
eo 0
v t
N) "(
,re1gff
nar/g")lsUi
o o]agtc:f
tro/vn,;hSsn
e#t;r>nr|S"r
mon);t>np:!
igl>0)r0si.(i "a )
R%(p
Ret t
t
Yn
O%(e
!lNc}=
3xi
g
rl n_e)s
n e=_n(
/o6‘sedwUreor
‘p1pe)eneOet
‘‘‘enrrLvsrc
{*t*d‘oLr*r(
)‘‘vieosoae>
‘‘ir_eaNsmv/
‘t_tmdz_inrs
t‘CeoOurp{u/
‘_ _nkofae
*‘‘r2urtrntht ;ssEisp
tr
_a
pRP(p
T"r
iEOff
uu
aISr )/
/
S
/‘‘‘‘‘]‘‘l‘‘‘s
‘‘‘‘‘‘[‘,‘‘‘‘
‘‘‘,‘‘‘r‘‘‘‘‘
‘‘‘‘‘‘‘‘‘‘‘‘(
‘‘‘‘l‘r‘r(‘‘‘
‘‘‘‘‘,‘l‘‘r‘*
a3‘a‘ae‘‘t
ctcocaiat
ol‘cno‘i
sgugidtt
aiie<v
nnnlt1
>i‘e‘h‘‘g‘a
ecz‘tt‘cm d<
svnoeS‘‘
*‘‘uor‘*e‘v‘>/ pi
mo
zear _/
ai/al
ap)l iFtII}
t/ii (_
rp
t>"" iil;E*
a>
p/
e
t‘/
tr
ir I
)S
(A
I
)A
(F
e
A
)*
Si
(}
h
_ ;S
a) AOIw
,stdae/IUDF
).n.ti*ZM1/
rd.dt ECCE
d)_ NI{F
ddn ONIl
_pd_
=ross (
aiasndoc"r
e_n (p
)_ar(h"sdnt
);sr(,:tef
dfiaon%eon
drson:tCi
od_t% n( E
C
;p i or
)(d& 1,nr
,0)rd_r)rdTp
r!rsrndtt*c
ar.sa cu(oi
_anae ;xc"e
oa "cr
)sti,sdstfn*
drizd)at,cO
d)sid*kcsnf
.ndot oeeeC
ds__ s/N/
d_a (tN
_d_ ()no
__
rso%te
.s _ (
_d i .
nd .I _
;.sn__nnp
)ss*d&c"
)r(,.uti
,_ 6% C
tih_TAme
pn .: g
a";:inn
sntFlad
d&sNgff
_ti.s=ar
/or.nnoi(i
r(a)r(rrt
pr(tE,,sr
sta1(yad
/riavcvaaor
a_
sgneig
zl
ioi
zs
aa
n
i
=SI
niatd .f/
eraro)_adnvlp
eedii ecV
ctr)nddzzesr
seet,sdlig<*
orotGddzi/0e
kue*sr(aidzd/
i/ a ri
c it"s
. t")r
n 1,co*
e ()ori
2tapro>ti ;x*((//
cl )ekrf f
8
0
07
2
6
28. cctaaoo/f Indice Codice Sorgente
ni//Na/lh/l
esegtpei
tnvbe/
.lrcalta/ :
c iaio
el/l m
r
usc > WS
)etih H t
ouk C ne
fs
lo D
od/ n_ow}
gi oTft
nud nndo
i RUd
‘‘‘‘‘‘‘‘;ss(u
‘‘;‘.‘‘{;n,(seit
oi
‘()‘.‘‘c"oi)p
‘‘‘,.: ‘)sn1
‘‘‘"‘‘ otss(
‘‘i‘‘ incnn
‘s‘%i ginDi
‘‘o ).n;r
‘/g eRt"h_nx
xf
ncfv
oe
di
it
sdD‘a
*peln‘nsnshsn <
2
)
c‘‘‘(‘"(
cr‘‘‘‘i
.soi‘i‘r
n‘)‘‘‘‘*
e‘‘‘‘‘ts
t(‘‘‘‘(p7
8t
3/‘‘‘‘)‘l‘‘‘‘‘c//0
0
2
ioniae>/6
29. Indice Codice Sorgente
eictaaoo/f
Mel/alta/ei
esegtp /l
knNa/lh/
a//vbe:
frcl io
l iam . a
****c**aoio
***e**vt)zr
***n e*tclh
#**in*aapi"@a"mz
#****o**donf@#
a oiL
***e tiemuc
* be *:ea*e
a**l***a$ml
#*****hbcc*"@c i
o* C
******t(in*on
**r***r$rhih*
******P*s*(**
****t"nrr*uca
***t*)****P**
i******zb‰:
***a*s*i**e
n***cilPPr
i*n*iotle
a**r***
m*:**
t*****
)*l.******
c*oniE
s*$******
t*e****#
t* A
e/*iN #
O********
j***p*****
lk*******
Onoa
jPaln
/ a
j"))oc
etPai
i$io
l/O
maozee
elelo
tT(f$Peo
P)b;cnkh
hoOhbnl"@
a$natidv tT(
/$sc
iiijbam
fbbb(sthbb(@
; f/nrn])j‰v
) )ob)hnbIm
ctaiat$
;$P(n$
ii;fbohbb(s@
adctijc is
lst$
tOf
POv
tb)lm
P)(($$(@
i(n)if
ipts)((!@
#**isn(zanff
#h(*;nrn]szoiosat[
*t$i)i]e/ndf
**ilib$u)i‰i
*a"ui(krhb!@
*Pir"$ntt$[
*nnt)kn;a$[
*o"ade)i‰i
* zheinhb i
ethiiP e
inmoao"@
i:znnc
zahi i a
uie l
#**acnbhh(!@
n*apebiu
osnPiloI
e*oiipntist
e*ee iaeo s
ae
d****n*ec:n
icbea uC
#****u*eedzo*i
#**.r*********
****.tr*r***l#
***l*t*******
***l*********
*l*t*vlr**l**
*l*tv*l***l**
a***tascniha
***a***ic*l
****s*eei* #
*** i
b***e*crt
s*tde *t
oceailt
o*lzst
e**t *
o*ntd
)rrorlear #
t*fo*r*N*#
TonT
Sl*oA
O*()*cl:***
j)l‰s*l****
Tsc*k*$**s
e$c**c***
s*$*(**o#
e*tlLI
lsoL
Htr**c)**
T*oogS
lk*(cs**** e
lk*e**
e)o‰:oc
b aosrTs lo d$cbt$
oot T
)e dooeoo setl(O (
TSkjk
ji es)$‰$c
loO$cfc
oTioS$c
otsei g
ejfr(
TlaHs
l lob()a‰
#**c*)kci)a)a
*n*r)jc)sr(O
******o**i:s
#*c*n$s*$*l:n$
#***b*sb(r***(O
****cb*sa s i
**‰*bos*f $f
*O*(*(
*oSj*oaz
*t$*il*iocfb$
*t*O*aa
#O*)Ot*** Sj(
**(***(k$*c**#
****s*$***()*
*****k*sjn$j*
***)*c)*)(*b*
***j(*j(c***c
*******S**e n
i
z*fg
iv
nbe
n*
p
e)ac
eO$
dsc
ei
i
******* *i
****f*i *l
*****i*O*
*****t*t*
******d
c:i
.ib
se* #
oto
lki
o*=
.Tt
st/
oc*
ocl
ee
ob
t** #
To=
/a
i*
h**=oll
.*bb*#
oc***
os**c
ebS*
odoc
t**t
/e*
l*bO
o*sj**
ll
skc**
Tsc=o
ib
lk.seAoo
FT
/t
Soc
Ili
.Ht=s
IsS
Alse
Foa
/Tf
Sik
hrTs
ie
da
li
be
.sH
obr
Sls=o
Aoa
Fas
/b
Iik
=k
cntO
i
e
Sf
ics
Of
ijc
***** .cn
***** ncl
***** erc
*
*
#****s clt
ee nji
#*****o t=e
si* t.i
i* ebl
#******i in=i
******* ihb
*****dc bt
******* la
*****i /P
****** .n
#*************
*************#
*************
****f********
*************
**eea*e*#
n**o*
#*****r******* aia
e****
T***r****
I****zD
L*ace**
C**oen
*******i*ne**
E*im***
ezomiM
dpppi
opcek
*************#
****l********
*****l*******
*************
*************
*********
N*rr**f**
1#*********f***
e*******
M*l****/
a******/
ei***l***
kl*****#
f**r****
l******* 8#
0
27
0#
6
30. .r Indice Codice Sorgente
cIce
An
S/s
Fie
b/l
./Nbeei
uiatp
ccalta//
svio :
)taaoh/l
il/lgm
(a/lo/f
gii
oiu
nme
iim
dea
tmemeo>rpr
nCneni/du
)aeaever;rtd
inenrnD)e=
ndlvoz/(o
rnttt(i i i
yaece p
)ii/el
iode
dini
(zoi
rneasz>
ai i /
ioddnoe/ n
dicelorn
(nHeuoe/
eldpi/
ineni
/a
/
oerdeoi//ppi
czaeiat
aanaP
)absaern/tt
im>gne
iVaocm
inigm
ldeaeern/mm
c)rmlceI;,t
ittidlaI21n
{llleC y
/erltr(eo0ci
HHtldvoc>en
HerlorCc =i
Hleseonr =i
HHltscto ;t
Hrlnnra> nn
Hdace> ;
Hbdyi o
Hnnnd t
*HH)Hdor/;rn
onltcxYts;rn
eHtr/0ui
zi,c XXi
adicancni
nHsHh(hc
o,ay,Ytt
irhrxacc
oH.HHHHHHHH
pHHHHHHHHHH
meridartktt
oHHHHHHH
eHHHHHHHHHH*miaitnci
inna
ix
aii e
is
a
iiHHHHH
nddnertcc
petsiimoI
ooiidaaR
nypyeo
reecaaeecan
gnie,oaes*
psoenc;no
edernsaonfo*
aiemdsai
ieHHeihn
Htlaorrs:ld:
HH.nrt1d,fae
Hadrscc"vrrl
.HHHHHlHHHHH
Havvdptcvtv*
HcorvHouolr*
Hatr:;sH.fc
aeiieHoscV ad0r
iaat
rHHHHl"HHHf
aHHHHHdHHc
eHHHHHcHHHi*
tlHHHH cHHH.
tHHHHliHHH
iHHHHH HHHH/
rei Y )*
vos k ><
ra e (
s
epe X 1
e h
mnev/f &
aami/ z
c
eptd>(sm
kie
)(ee>) y
)rna/ e
rdr' _
;irii)orI
nogi
aet
hzse/n,easu
isc)),e(}
.fT,
bmg
/;;Ey&a i
rcrllE;((bsl
nnan_fobfR
al/utmdF
pRiinn
>N()ia
elslrR,ee,aF
ffvnt>)Mede
fl)(sE0elel
uk)n™tnzrde
bckecaLicf
i*ae0NAD(
icviN],ii
iCeMEet
iIAisn
lov/tNf
%i/L;l)Eb>_,
)k;,tu
=ufR
>s(l
nfl
Nccdr
LntsWe&F
Er[el
Affl
Mkrdu
iem
_ue
M(
Neim
z(sw
znu
efd)r(/
mikrt
a™,b/
ene
uf
iaLro
_hsi
MntP
=teAe
Ns
E"y
l
gfnt
nnt
nr
ec
kfpts
i(r
lh
n,:lasEN)"(
tietcs1Lri
i"kitn);r(p
dncrios)c"c
sdnpnamr(s
ndkcq)NAirp
omnsc Len(
saliA E);n
sc i/ ;,f
eaNis>"ENs(s
ieieu/Rc(r k)aa
>lh}
si
tc
"g
%fe
/e ;eiefd
Hn nnent
Hc :cinn
H mnI
H at
*nHt/ kiMi
.oa u_ o
ik/ goi(
eHeourdnH[i
teltiso{(0c
iarHNaar!ca
rlsle t)nf{
po;cc;Fgoi
es> nodv
iv rceg
tloeve])]n
armdreEnda
ptse ;Uoe s0kf
a=
sXe
ciai
nA R
es ev[e
drHaFifh
feomduit
iHnHduc
HHHHHHHHHH'H
HHlHlHHHHHlH
HHHHHHlHHHHH
HHHHHHlH:HHH
HHHHHHHHlHH*
HHHHHHHHHHH kBrg
inHi
isr
idL
ntb*
gHc
ilcs
iv*
de o
>t
eHHHHHnH;HH.
bHHHHHgHHlH(
iHHHHHoHHHe<
lHHHHHiHHHH1
s.HHHH HHHr*
iHc Hbq
Envhn>li)ne
_IHHHHHHHHb/
EVtr/ _ln
Lra / Eei
N ils
QBIeeA0R=s(}
RSaag =sev* 1oor
is
ie
vHsP
s)
&vl
/vHHsrSQBIIf
HiHHol(biir
HHanhe)LNDl
HHlHc>enbii
HHHti;lr=(
Hatag/iIif
Hai /sVei
*IèfiaiEI=e
/HHHHHH""HHH ISsl
e ))I,ai
enzqdoa
HHHHHHeieess
HHHHrofrtrW*
HHHHHisDedi
HHHHszoautu
HHHH tenqiF
HHHHH;ueeftt
r )q,s(c
su( >
eqhv
HHHHHHHHHHHH
HHHHHHHHHHHH
HHHHHHHHHHH*
HHHHHHHHHHH/
HHHHHH.HHHH
>HHaesHH
rr{qfe)*
piItii1
*HHHvasHHHHf z<Hè
eoDturt
eeDsrcC
1HrniHHH
)HsHncifFva
icodHH<
iusuE
iiae o
HHHHHHHHHHH(
HHHHHHHHHHHH
HHH.HHHH(HH*
HHHHHHeHHlH/
HHHHlHrHHH.
HHHcdHHt*
HtnrHHH
*HHHHHvHHHHH
1/HHHHHH>HHHHH#
F1HH"HH
. (HHH"H
cIH<HH.HH
A)HHHHH//
SHHHHHHi Ie
Au
hHc
Sd
Fln
7
8*
0/
0
26