HostState_t                             State;     /* stato server  */



  - GENERALITA':
    ============


          SERVER
          ------

  Il server e' stato realizzato secondo uno schema concorrente

  a singolo processo, basato sulla gestione in multiplex dell'I/O

  ottenuta mediante utilizzo della funzione "select()".


  Questo evita di dover gestire l'accesso simultaneo al catalogo

  di biblioteca, e risulta essere piu' efficiente rispetto ad una

  soluzione multiprocesso in termini di utilizzo delle risorse di sistema.


  Le operazioni di scrittura sono effettuate in modo non bloccante

  (ottenuto mediante fcntl()) per garantire l'avanzamento delle richieste

  ed il ritorno al trattamento della select()  anche in caso di riempimento

  dei buffer di comunicazione.

  Questo permette di evitare condizioni di blocco, sia per arresto

  della ricezione da parte del client, che durante fasi di trasmissione

  reciproca tra server.


  Il meccanismo di inoltro della risposta sfrutta viene quindi messo in moto

  dalla disponibilita di buffer sia in caso locale che remoto.



           Struttura Protocollo

  Il protocollo consiste in due funzioni che gestiscono l'input da socket,

  e due l'output.

  Le ReadMessage/WriteMessage si occupano della lettura/scrittura di un

  singolo messaggio da/su buffer della socket.

  Le HandleRead/HandleWrite gestiscono la logica di protocollo interno ed

  il controllo delle abilitazioni.


  L'alternarsi delle varie fasi di lettura e scrittura sulla stessa socket

  nel corso dell'elaborazione della query viene ottenuto mediante

  l'utilizzo di due funzioni: "SetWriteToken" e "SetReadToken" che impostano

  i bit delle rispettive strutture fds, e di variabili di stato associate

  alla socket.

  Per ogni singola fase di scrittura/lettura ci si preoccupa di disabilitare

  inizialmente il token e di abilitare correttamente in funzione dello stato

  corrente la fase successiva,


  Il collegamento tra server avviene attraverso registrazione esplicita ai

  server gia' attivi e comunicazione dei propri indirizzo e porta.

  La connessione utilizzata in questa fase viene poi mantenuta attiva allo

  scopo di segnalare quando interrota la caduta di uno dei due server.


  Da notare che i dati ed il buffer relativi ad ogni socket sono contenuti in

  una struttura di tipo SockInfo, i cui dettagli sono illustrati nel

  seguito.


  Passiamo a descrivere il ciclo tipico di utilizzo: la risposta a richiesta

  del client.


  Dopo la accept il token viene dato alla socket del client in lettura.

  Si effettua la lettura della query e si inizializza la SockInfo per la

  ricerca locale, abilitata mediante WriteToken.

  Ogni fase della ricerc locale viene pilotata dal completamento della

  precedente col meccanismo di abilitazione del token in scrittura.


  Terminata la ricerca locale si modifica la Sockinfo in modo da proseguire

  con la remota.

  Qui per ogni server remoto si inoltra la richiesta e si passa il token in

  lettura alla socket del server.

  Per ogni messaggio di risposta ricevuto vi e' un passaggio del token alla

  write su client, il cui completamento determina il passaggio del token

  nuovamente alla read da server per la successiva risposta.

  Ogni ciclo di interrogazione del server remoto termina quando si verifica

  la condizione di EOF, dando avvio alla fase di connect sul server

  successivo.


  Alla chiusura dell'ultimo server si chiude anche la connessione col client,

  segnalandogli cosi' il completamento della query.


  Le operazioni di aggiornamento del catalogo sono svolte dal bibliotecario

  tramite stdio, trattato in select in modo tale da permettere l'elaborazione

  concorrente.



          CLIENT
          ------

  Il meccanismo illustrato sopra permette di realizzare un client che non sia

  a conoscenza delle problematiche della rete ma che semplicemente realizza

  la query tramite una operazione di write e successive letture delle

  risposte.

  La versione da noi realizzata alterna l'input a fasi di ricezione risposte.

  Questo protocollo rende comunque possibile espandere a piacere il client

  senza che siano necessarie modifiche al server.






  - PROTOCOLLO CONTROLLO SERVER:
    ============================

      Server A               Server N
      ========               ========



     1) listen()
                            2) listen()
     3) connect()
                            4) accept()
                            5) write(control)
    6) read(control)

        ...                  ...

 Caso A) .....
                            7) close()
   8) read(EOF)

   9) close()


 Caso B) .....

   7) close()
                           8) read(EOF)

                           9) close()








    - PROTOCOLLO RICHIESTA/RISPOSTA:
      ==============================



     Client              Server A               Server N
     ======              ========               ========


                         1) listen()             1) listen()

                            ...                     ...

     2) connect()
                                                3) accept()

     4) write(query)
                                                5) read(query)

                                                6) write(reply)*
     7) read(reply)*                                                           per ogni server
                                                      <-------------------------------+
                                                8) connect()                          |
                                                                                9) accept()  
                                                                                      |            
                                               10) write(query)                       | 
                                                                               11) read(query)
                                                                                      |
                                                                               12) write(reply)*
                                                                                      |
                                               13) read(reply)*                       |
                                                                                      |
                                               14) write(reply)*                      |
                                                                                      |
       15) read(reply)*                                                               |
                                                                                16) close()
                                                                                      |
                                                      >-------------------------------+
                                                17) close()
       18) close()






   - STRUTTURE DATI:
         ===============



  SocketInfo_t:  
  -------------------------


 Viene utilizzata come descrittore per le socket attive,

 mantenendone le informazioni di stato relative.


 In modo particolare, viene evidenziata la presenza di un buffer di I/O

  differenziato per ogni socket, che permette l'avanzamento parallelo di

  piu' richieste.


 Queste strutture vengono allocate dinamicamente e gestite tramite un

    array statico di puntatori, indicizzato dall'identificativo della socket.



   typedef struct SocketInfo_tag
   {
     SocketType_t            Type;       /* tipo di socket distinta in
                                            client/server/control */
     SocketState_t           State;      /* stato operazioni i/o messaggi
                                            da/verso buffer */
     SocketControl_t         Control;    /* stato  avanzamento richiesta (se
                                            client) */
     int                     Request;    /* indice avanzamento scansione server */
     long                    Offset;     /* Offset avanzamento ricerca locale
                                            su file  */
     int                     Linked;     /* socket destinazione (per server) */
     int                     NoForward;  /* flag per inibizione inoltro
                                            ad altri server */
     Libro_t                 Libro;      /* struttura dati query/riposte */
     int                     Len;        /* lunghezza messaggio  */
     int                     ToRead;     /* numero bytes rimanenti da leggere  */
     int                     ToWrite;    /* numero bytes rimanenti da scrivere */
     MessageText_t           Text;       /* buffer messaggio */

    } SocketInfo_t;





  HostInfo_t:  
  -----------------------


  Contiene alcuni dati relativi ai server collegati, tra cui l'indirizzo

  della socket in listen.

  Queste strutture sono memorizzate in un array statico a cui si accede

  in modo sequenziale durante lo svolgimento delle richieste.

  I dati del primo elemento si rifericono al server locale.



     typedef struct HostInfo_tag
     {
      int                  Inactive;   /* flag annullamento host */
      HostState_t          State;     /* stato server  */
      Biblio_t             Biblio;         /* nome descrittivo biblioteca */
      int                  Socket;     /* socket (connected/accepted)  */
      struct sockaddr_in   Peer;       /* host:port peer se accepted  */

     } HostInfo_t;





  Array Fds:  
  ----------------------


   Vengono utilizzati a coppie quattro array fd_set, due per le operazioni

 di lettura e due per la scrittura, differenziati in Active e Select,

    da utilizzarsi rispettivamente come salvataggio e input/output

  verso la select.





  Libro_t:  
  -------------------


      Definisce la struttura delle informazioni applicative, e viene

  utilizzata sia come formato di richiesta che per le risposte all'utente.



     typedef struct Libro_tag
     {
       char Titolo[LEN_TITOLO];    /* titolo libro */
       char Autore[LEN_AUTORE];    /* autore libro */
       char Anno[LEN_ANNO];        /* anno edizione libro */
     } Libro_t;







    - MODULI:
         =======


       CLIENT:


         client.c                /* main e funzioni varie del client     */


      SERVER:


         main.c          /* Parsing parametri ed inizializzazione */

             server.c                /* Gestione del lato server */


  COMUNI:


         socket.c                /* Strutture e funzioni gestione socket */

              message.c   /* Trattamento messaggi e conversione da/a buffer */

                libro.c         /* Gestione accesso catalogo biblioteca */

              support.c       /* Funzioni di utilita' varia */





        - CENNI SULL'UTILIZZO:
    ====================


    Avvio Server


    server -h attiva l'aiuto in linea.


      Attivare il primo server con

    server -f  -b 

              Es:

             server -f c1.txt -b biblio1

     Attivare i successivi server comunicandogli anche porta ed indirizzo

    degli altri server precedentemente annotati.

            Es:

             server -f c3.txt -b biblio3 host1:port1 host2:port2


     Funzione Bibliotecario

          A server attivo la pressione dell'enter elenca i comandi disponibili.



   Client

          Attivare col comando client.

    Quando richiesto immettere host e port di un server attivo, ed

          immettere la chiave di ricerca.


                 Es: ( basato sui file c1.txt c2.txt c3.txt forniti a corredo ed
                                       utilizzati per i test )

           client


                        alla richiesta 'host:', immettere l'indirizzo di un server
                      alla richiesta 'port:', immettere la porta di un server

                 alla richiesta di chiave digitare:
                      itolo 1


                 sul terminale appaiono di seguito i libri i cui titoli sono:

                    1Titolo 1
                       1Titolo 10

                      2Titolo 1
                       2Titolo 10

                      3Titolo 1
                       3Titolo 10

                      completi di tutti i dati nonche' del server di provenienza.

                     NOTA: Chiaramente l'ordine di inoltro ai server puo' varire e
                                   di conseguenza l'ordine delle risposte.