SlideShare a Scribd company logo
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
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
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
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
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
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
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
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
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
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
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
- 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
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
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
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
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
•    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
•     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
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
/*! 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
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
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
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
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
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
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
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
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
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
.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
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale
Battaglia Navale

More Related Content

What's hot

Seminario introduzione all'uso del terminale e della bash in Linux
Seminario introduzione all'uso del terminale e della bash in LinuxSeminario introduzione all'uso del terminale e della bash in Linux
Seminario introduzione all'uso del terminale e della bash in Linux
alberto fiaschi
 
Linux Kernel, driver e compilazione
Linux Kernel, driver e compilazioneLinux Kernel, driver e compilazione
Linux Kernel, driver e compilazione
Fulvio Corno
 
Netbeans e Xdebug per debugging e profiling di applicazioni PHP
Netbeans e Xdebug per debugging e profiling di applicazioni PHPNetbeans e Xdebug per debugging e profiling di applicazioni PHP
Netbeans e Xdebug per debugging e profiling di applicazioni PHPGiorgio Cefaro
 
PostgreSQL : Tuning
PostgreSQL : TuningPostgreSQL : Tuning
PostgreSQL : Tuning
Enrico Pirozzi
 
Moduli del kernel - Boot del sistema
 Moduli del kernel - Boot del sistema Moduli del kernel - Boot del sistema
Moduli del kernel - Boot del sistema
Fulvio Corno
 
PostgreSQL: Prima configurazione
PostgreSQL: Prima configurazionePostgreSQL: Prima configurazione
PostgreSQL: Prima configurazione
Enrico Pirozzi
 
Apache HTTP Server
Apache HTTP ServerApache HTTP Server
Apache HTTP Server
Mariano Fiorentino
 
SVN/TRAC
SVN/TRACSVN/TRAC
SVN/TRAC
Diego La Monica
 
TYPO3 CMS 7.6 - Le novita
TYPO3 CMS 7.6 - Le novitaTYPO3 CMS 7.6 - Le novita
TYPO3 CMS 7.6 - Le novita
Roberto Torresani
 
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
Fulvio Corno
 
Linux shell
Linux shellLinux shell
Linux shell
Marco Buttolo
 
TYPO3 Versione 10.1 - Le novita
TYPO3 Versione 10.1 - Le novitaTYPO3 Versione 10.1 - Le novita
TYPO3 Versione 10.1 - Le novita
Roberto Torresani
 
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
 La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
Fulvio Corno
 
Tools & librerie PHP
Tools & librerie PHPTools & librerie PHP
Tools & librerie PHP
Augusto Silvino
 

What's hot (14)

Seminario introduzione all'uso del terminale e della bash in Linux
Seminario introduzione all'uso del terminale e della bash in LinuxSeminario introduzione all'uso del terminale e della bash in Linux
Seminario introduzione all'uso del terminale e della bash in Linux
 
Linux Kernel, driver e compilazione
Linux Kernel, driver e compilazioneLinux Kernel, driver e compilazione
Linux Kernel, driver e compilazione
 
Netbeans e Xdebug per debugging e profiling di applicazioni PHP
Netbeans e Xdebug per debugging e profiling di applicazioni PHPNetbeans e Xdebug per debugging e profiling di applicazioni PHP
Netbeans e Xdebug per debugging e profiling di applicazioni PHP
 
PostgreSQL : Tuning
PostgreSQL : TuningPostgreSQL : Tuning
PostgreSQL : Tuning
 
Moduli del kernel - Boot del sistema
 Moduli del kernel - Boot del sistema Moduli del kernel - Boot del sistema
Moduli del kernel - Boot del sistema
 
PostgreSQL: Prima configurazione
PostgreSQL: Prima configurazionePostgreSQL: Prima configurazione
PostgreSQL: Prima configurazione
 
Apache HTTP Server
Apache HTTP ServerApache HTTP Server
Apache HTTP Server
 
SVN/TRAC
SVN/TRACSVN/TRAC
SVN/TRAC
 
TYPO3 CMS 7.6 - Le novita
TYPO3 CMS 7.6 - Le novitaTYPO3 CMS 7.6 - Le novita
TYPO3 CMS 7.6 - Le novita
 
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
Condivisione di dischi - NFS - Reti miste Windows/Linux - SMB e NetBIOS - Sam...
 
Linux shell
Linux shellLinux shell
Linux shell
 
TYPO3 Versione 10.1 - Le novita
TYPO3 Versione 10.1 - Le novitaTYPO3 Versione 10.1 - Le novita
TYPO3 Versione 10.1 - Le novita
 
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
 La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
La shell Bash - Comandi base - Comandi avanzati - Espressioni regolari
 
Tools & librerie PHP
Tools & librerie PHPTools & librerie PHP
Tools & librerie PHP
 

Viewers also liked

festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...
festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...
festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...festival ICT 2016
 
Monitoraggio della rete con cacti
Monitoraggio della rete con cactiMonitoraggio della rete con cacti
Monitoraggio della rete con cacti
dalegiuseppe
 
Nagios
NagiosNagios
Nagios
Juan Avila V
 
CACTI - Network Graphing Solution
CACTI - Network Graphing SolutionCACTI - Network Graphing Solution
CACTI - Network Graphing SolutionVitor Ivan D'Angelo
 
CACTI: Monitoramento Inteligente de Redes - Gabriel Stein
CACTI: Monitoramento Inteligente de Redes - Gabriel SteinCACTI: Monitoramento Inteligente de Redes - Gabriel Stein
CACTI: Monitoramento Inteligente de Redes - Gabriel SteinTchelinux
 
Cacti presentation
Cacti presentationCacti presentation
Cacti presentation
Didiet A. Pambudiono
 
Infrastructure - Monitoring - Cacti
Infrastructure - Monitoring - CactiInfrastructure - Monitoring - Cacti
Infrastructure - Monitoring - Cacti
Frédéric FAURE
 

Viewers also liked (9)

festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...
festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...
festival ICT 2013: Gestire criticità in maniera efficiente per liberare slot ...
 
Monitoraggio della rete con cacti
Monitoraggio della rete con cactiMonitoraggio della rete con cacti
Monitoraggio della rete con cacti
 
Coaching emozionale
Coaching emozionaleCoaching emozionale
Coaching emozionale
 
Nagios
NagiosNagios
Nagios
 
CACTI - Network Graphing Solution
CACTI - Network Graphing SolutionCACTI - Network Graphing Solution
CACTI - Network Graphing Solution
 
Cacti
CactiCacti
Cacti
 
CACTI: Monitoramento Inteligente de Redes - Gabriel Stein
CACTI: Monitoramento Inteligente de Redes - Gabriel SteinCACTI: Monitoramento Inteligente de Redes - Gabriel Stein
CACTI: Monitoramento Inteligente de Redes - Gabriel Stein
 
Cacti presentation
Cacti presentationCacti presentation
Cacti presentation
 
Infrastructure - Monitoring - Cacti
Infrastructure - Monitoring - CactiInfrastructure - Monitoring - Cacti
Infrastructure - Monitoring - Cacti
 

Similar to Battaglia Navale

PIT2012: Workshop@UniNA - Compilazione del Kernel Linux
PIT2012: Workshop@UniNA - Compilazione del Kernel LinuxPIT2012: Workshop@UniNA - Compilazione del Kernel Linux
PIT2012: Workshop@UniNA - Compilazione del Kernel LinuxMarco Ferrigno
 
Hadoop analyzerJR
Hadoop analyzerJRHadoop analyzerJR
Hadoop analyzerJR
Simone Romano
 
Idp, passo dopo passo!
Idp, passo dopo passo!Idp, passo dopo passo!
Idp, passo dopo passo!
Claudio Marotta
 
Pacchi e pacchetti
Pacchi e pacchettiPacchi e pacchetti
Pacchi e pacchetti
giallu
 
Apache Maven - Gestione di progetti Java e build automation
Apache Maven - Gestione di progetti Java e build automationApache Maven - Gestione di progetti Java e build automation
Apache Maven - Gestione di progetti Java e build automation
Tiziano Serritella
 
Installazione del cms alfresco
Installazione del cms alfrescoInstallazione del cms alfresco
Installazione del cms alfresco
Mirco Leo
 
Progettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computer
Alessandro Mascherin
 
TuxIsAlive
TuxIsAliveTuxIsAlive
TuxIsAlive
Claudio Mignanti
 
Docker & DevOps
Docker  & DevOpsDocker  & DevOps
Docker & DevOps
Gerardo Di Iorio
 
TYPO3 CMS 6.2 LTS - Le Novità
TYPO3 CMS 6.2 LTS - Le NovitàTYPO3 CMS 6.2 LTS - Le Novità
TYPO3 CMS 6.2 LTS - Le Novità
Roberto Torresani
 
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
LeonardoIurada
 
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Mattia Milleri
 
SPRING - MAVEN - REST API (ITA - Luglio 2017)
SPRING - MAVEN - REST API (ITA - Luglio 2017)SPRING - MAVEN - REST API (ITA - Luglio 2017)
SPRING - MAVEN - REST API (ITA - Luglio 2017)
Valerio Radice
 
Introduzione ros
Introduzione rosIntroduzione ros
Introduzione ros
Marco Buttolo
 
Back to Basics, webinar 6: Messa in esercizio
Back to Basics, webinar 6: Messa in esercizioBack to Basics, webinar 6: Messa in esercizio
Back to Basics, webinar 6: Messa in esercizio
MongoDB
 
MITM Attack with Patching Binaries on the Fly by Adding Shellcodes
MITM Attack with Patching Binaries on the Fly by Adding ShellcodesMITM Attack with Patching Binaries on the Fly by Adding Shellcodes
MITM Attack with Patching Binaries on the Fly by Adding Shellcodes
Gianluca Gabrielli
 
Capitolo 7 elementi di programmazione c-c++
Capitolo 7   elementi di programmazione  c-c++Capitolo 7   elementi di programmazione  c-c++
Capitolo 7 elementi di programmazione c-c++Giovanni Della Lunga
 
Buffer Overflow - Shellcode - Shatter Attack
Buffer Overflow - Shellcode - Shatter AttackBuffer Overflow - Shellcode - Shatter Attack
Buffer Overflow - Shellcode - Shatter Attack
luigi capuzzello
 

Similar to Battaglia Navale (20)

PIT2012: Workshop@UniNA - Compilazione del Kernel Linux
PIT2012: Workshop@UniNA - Compilazione del Kernel LinuxPIT2012: Workshop@UniNA - Compilazione del Kernel Linux
PIT2012: Workshop@UniNA - Compilazione del Kernel Linux
 
Hadoop analyzerJR
Hadoop analyzerJRHadoop analyzerJR
Hadoop analyzerJR
 
Idp, passo dopo passo!
Idp, passo dopo passo!Idp, passo dopo passo!
Idp, passo dopo passo!
 
Pacchi e pacchetti
Pacchi e pacchettiPacchi e pacchetti
Pacchi e pacchetti
 
Apache Maven - Gestione di progetti Java e build automation
Apache Maven - Gestione di progetti Java e build automationApache Maven - Gestione di progetti Java e build automation
Apache Maven - Gestione di progetti Java e build automation
 
Installazione del cms alfresco
Installazione del cms alfrescoInstallazione del cms alfresco
Installazione del cms alfresco
 
ORM Java - Hibernate
ORM Java - HibernateORM Java - Hibernate
ORM Java - Hibernate
 
Progettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computer
 
TuxIsAlive
TuxIsAliveTuxIsAlive
TuxIsAlive
 
Docker & DevOps
Docker  & DevOpsDocker  & DevOps
Docker & DevOps
 
TYPO3 CMS 6.2 LTS - Le Novità
TYPO3 CMS 6.2 LTS - Le NovitàTYPO3 CMS 6.2 LTS - Le Novità
TYPO3 CMS 6.2 LTS - Le Novità
 
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
 
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
 
SPRING - MAVEN - REST API (ITA - Luglio 2017)
SPRING - MAVEN - REST API (ITA - Luglio 2017)SPRING - MAVEN - REST API (ITA - Luglio 2017)
SPRING - MAVEN - REST API (ITA - Luglio 2017)
 
Introduzione ros
Introduzione rosIntroduzione ros
Introduzione ros
 
Back to Basics, webinar 6: Messa in esercizio
Back to Basics, webinar 6: Messa in esercizioBack to Basics, webinar 6: Messa in esercizio
Back to Basics, webinar 6: Messa in esercizio
 
MITM Attack with Patching Binaries on the Fly by Adding Shellcodes
MITM Attack with Patching Binaries on the Fly by Adding ShellcodesMITM Attack with Patching Binaries on the Fly by Adding Shellcodes
MITM Attack with Patching Binaries on the Fly by Adding Shellcodes
 
Capitolo 7 elementi di programmazione c-c++
Capitolo 7   elementi di programmazione  c-c++Capitolo 7   elementi di programmazione  c-c++
Capitolo 7 elementi di programmazione c-c++
 
Logging
LoggingLogging
Logging
 
Buffer Overflow - Shellcode - Shatter Attack
Buffer Overflow - Shellcode - Shatter AttackBuffer Overflow - Shellcode - Shatter Attack
Buffer Overflow - Shellcode - Shatter Attack
 

Battaglia Navale

  • 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