Due correzioni dell'indirizzo del CVS.
[gapil.git] / tcpsockadv.tex
index d22c6aa84ab43a5696de32e2346915e11a11424c..991fe0494a2590eac0e2ade576fd81e167d1d7df 100644 (file)
@@ -1,4 +1,4 @@
- %% tcpsockadv.tex
+%% tcpsockadv.tex
 %%
 %% Copyright (C) 2003 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
@@ -365,7 +365,7 @@ Ci si pu
 quando questa sembra rendere \funcd{shutdown} del tutto equivalente ad una
 \func{close}. In realtà non è così, esiste infatti un'altra differenza con
 \func{close}, più sottile. Finora infatti non ci siamo presi la briga di
-sottolineare in maniera esplicita che come per i file e le fifo, anche per i
+sottolineare in maniera esplicita che, come per i file e le fifo, anche per i
 socket possono esserci più riferimenti contemporanei ad uno stesso socket. Per
 cui si avrebbe potuto avere l'impressione che sia una corrispondenza univoca
 fra un socket ed il file descriptor con cui vi si accede. Questo non è
@@ -377,30 +377,32 @@ fanno riferimento allo stesso socket.
 Allora se avviene uno di questi casi quello che succederà è che la chiamata a
 \func{close} darà effettivamente avvio alla sequenza di chiusura di un socket
 soltanto quando il numero di riferimenti a quest'ultimo diventerà nullo.
-Fintanto che ci sono file descriptor che fanno riferimento ad un socket
-\func{close} si limiterà a deallocare nel processo corrente il file descriptor
-utilizzato, ma il socket resterà pienamente accessibile attraverso gli altri
-riferimenti.Se torniamo all'esempio di \figref{fig:TCP_echo_server_first_code}
-abbiamo infatti che le due \func{close} (sul socket connesso nel padre e sul
-socket in ascolto nel figlio), restando comunque altri riferimenti attivi (al
-socket connesso nel figlio e a quello in ascolto nel padre) non effettuano
-nessuna chiusura effettiva.  
-
-Questo non avviene affatto se si usa \func{shutdown} al posto di \func{close},
-in questo caso infatti la chiusura del socket viene effettuata immediatamente,
-indipendentemente dalla presenza di altri riferimenti attivi, e pertanto sarà
-ovviamente efficace anche per tutti gli altri file descriptor con cui si fa
+Fintanto che ci sono file descriptor che fanno riferimento ad un socket l'uso
+di \func{close} si limiterà a deallocare nel processo corrente il file
+descriptor utilizzato, ma il socket resterà pienamente accessibile attraverso
+tutti gli altri riferimenti. Se torniamo all'esempio originale del server di
+\figref{fig:TCP_echo_server_first_code} abbiamo infatti che ci sono due
+\func{close}, una sul socket connesso nel padre, ed una sul socket in ascolto
+nel figlio, ma queste non effettuano nessuna chiusura reale di detti socket,
+dato che restano altri riferimenti attivi, uno al socket connesso nel figlio
+ed uno a quello in ascolto nel padre.
+
+Questo non avviene affatto se si usa \func{shutdown} con argomento
+\macro{SHUT\_RDWR} al posto di \func{close}; in questo caso infatti la
+chiusura del socket viene effettuata immediatamente, indipendentemente dalla
+presenza di altri riferimenti attivi, e pertanto sarà efficace anche per tutti
+gli altri file descriptor con cui, nello stesso o in altri processi, si fa
 riferimento allo stesso socket.
 
 Il caso più comune di uso di \func{shutdown} è comunque quello della chiusura
 del lato in scrittura, per segnalare all'altro capo della connessione che si è
 concluso l'invio dei dati, restando comunque in grado di ricevere quanto
-ancora questi potrà inviarci. Questo è ad esempio l'uso che ci serve per
-rendere finalmente completo il nostro esempio sul servizio echo. Il nostro
-client infatti presenta ancora un problema, che nell'uso che finora ne abbiamo
-fatto non è emerso, ma che ci aspetta dietro l'angolo non appena usciamo
-dall'uso interattivo e proviamo ad eseguirlo redirigendo standard input e
-standard output. Così se eseguiamo:
+questi potrà ancora inviarci. Questo è ad esempio l'uso che ci serve per
+rendere finalmente completo il nostro esempio sul servizio \textit{echo}. Il
+nostro client infatti presenta ancora un problema, che nell'uso che finora ne
+abbiamo fatto non è emerso, ma che ci aspetta dietro l'angolo non appena
+usciamo dall'uso interattivo e proviamo ad eseguirlo redirigendo standard
+input e standard output. Così se eseguiamo:
 \begin{verbatim}
 [piccardi@gont sources]$ ./echo 192.168.1.1 < ../fileadv.tex  > copia
 \end{verbatim}%$
@@ -413,30 +415,32 @@ dimensione massima pari a \texttt{MAXLINE} per poi scriverlo, alla massima
 velocità consentitagli dalla rete, sul socket. Dato che la connessione è con
 una macchina remota occorre un certo tempo perché i pacchetti vi arrivino,
 vengano processati, e poi tornino indietro. Considerando trascurabile il tempo
-di processo, questo tempo, detto RTT (da \textit{Round Trip Time} può essere
-stimato con l'uso del comando \cmd{ping}. Ma mantre il pacchetti sono in
-transito sulla rete il client continua a leggere e a scrivere fintanto che il
-file in ingresso finisce. 
+di processo, questo tempo è quello impiegato nella trasmissione via rete, che
+viene detto RTT (dalla denominazione inglese \textit{Round Trip Time}) ed è
+quello che viene stimato con l'uso del comando \cmd{ping}.
 
 A questo punto, se torniamo al codice mostrato in
-\figref{fig:TCP_ClientEcho_third}, notiamo che non appena viene ricevuto un
-end-of-file in ingresso il nostro client termina. Nel caso interattivo, in cui
-si inviavano brevi stringe una alla volta, c'era sempre il tempo di eseguire
-la lettura completa di quanto il server rimandava indietro. In questo caso
-però quando il client termina, essendo la comunicazione a piena velocità, ci
-saranno ancora pacchetti in transito sulla rete, ma siccome il client esce
-immediatamente dopo la fine del file in ingresso, questi non faranno a tempo a
-completare il percorso e verranno persi.
-
-Per evitare questo tipo di problema occorre, invece di uscire, usare
-\func{shutdown} per effettuare la chiusura del socket in scrittura una volta
-completata la lettura del file in ingresso. In questo modo il client segnalerà
+\figref{fig:TCP_ClientEcho_third}, possiamo vedere che mentre i pacchetti sono
+in transito sulla rete il client continua a leggere e a scrivere fintanto che
+il file in ingresso finisce. Però non appena viene ricevuto un end-of-file in
+ingresso il nostro client termina. Nel caso interattivo, in cui si inviavano
+brevi stringhe una alla volta, c'era sempre il tempo di eseguire la lettura
+completa di quanto il server rimandava indietro. In questo caso invece, quando
+il client termina, essendo la comunicazione saturata e a piena velocità, ci
+saranno ancora pacchetti in transito sulla rete che devono arrivare al server
+e poi tornare indietro, ma siccome il client esce immediatamente dopo la fine
+del file in ingresso, questi non faranno a tempo a completare il percorso e
+verranno persi.
+
+Per evitare questo tipo di problema, invece di uscire una volta completata la
+lettura del file in ingresso, occorre usare \func{shutdown} per effettuare la
+chiusura del lato in scrittura del socket. In questo modo il client segnalerà
 al server la chiusura del flusso dei dati, ma potrà continuare a leggere
-quanto il server gli sta ancora inviando fino a quando quest'ultimo,
+quanto il server gli sta ancora inviando indietro, fino a quando anch'esso,
 riconosciuta la chiusura del socket in scrittura da parte del client,
-effettuerà la chiusura dello stesso a sua volta. Solo alla ricezione della
-chiusura del socket da parte del server, si potrà essere sicuri della
-ricezione di tutti i dati prima della terminazione della connessione.
+effettuerà la chiusura dalla sua parte. Solo alla ricezione della chiusura del
+socket da parte del server il client potrà essere sicuro della ricezione di
+tutti i dati e della terminazione effettiva della connessione.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -472,19 +476,20 @@ successiva (\texttt{\small 16}) chiamata a \func{select}.
 
 Le maggiori modifiche rispetto alla precedente versione sono invece nella
 gestione (\texttt{\small 18--22}) del caso in cui la lettura con \func{fgets}
-restitisca un valore nullo, indice della fine del file, che prima causava
-l'immediato ritorno della funzione. In questo caso prima (\texttt{\small 19})
-si imposta opportunamente \var{eof} ad un valore non nullo, dopo di che
-(\texttt{\small 20}) si effettua la chiusura del lato in scrittura del socket
-con \func{shutdown}. Infine (\texttt{\small 21}) si usa la macro
-\macro{FD\_CLR} per togliere lo standard input dal file descriptor set.
+restituisce un valore nullo, indice della fine del file. Questa nella
+precedente versione causava l'immediato ritorno della funzione; in questo caso
+prima (\texttt{\small 19}) si imposta opportunamente \var{eof} ad un valore
+non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato
+in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si
+usa la macro \macro{FD\_CLR} per togliere lo standard input dal file
+descriptor set.
 
 In questo modo anche se la lettura del file in ingresso è conclusa, la
 funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua
 ad eseguirlo ripetendo la chiamata a \func{select} per tenere sotto controllo
 soltanto il socket connesso, dal quale possono arrivare altri dati, che
 saranno letti (\texttt{\small 31}), ed opportunamente trascritti
-(\texttt{\small 44--48}) sullo standard input.
+(\texttt{\small 44--48}) sullo standard output.
 
 Il ritorno della funzione, e la conseguente terminazione normale del client,
 viene invece adesso gestito all'interno (\texttt{\small 30--49}) della lettura
@@ -495,8 +500,340 @@ diversa a seconda del valore di \var{eof}. Se infatti questa 
 ingresso, vorrà dire che anche il server ha concluso la trasmissione dei dati
 restanti, e si potrà uscire senza errori, altrimenti si stamperà
 (\texttt{\small 40--42}) un messaggio di errore per la chiusura precoce della
-connesione.
+connessione.
+
+
+\subsection{Un server basato sull'I/O multiplexing}
+\label{sec:TCP_serv_select}
+
+Seguendo di nuovo le orme di Stevens in \cite{UNP1} vediamo ora come con
+l'utilizzo dell'I/O multiplexing diventi possibile riscrivere completamente il
+nostro server \textit{echo} con una architettura completamente diversa, in
+modo da evitare di dover creare un nuovo processo tutte le volte che si ha una
+connessione.\footnote{ne faremo comunque una implementazione diversa rispetto
+  a quella presentata da Stevens in \cite{UNP1}.}
+
+La struttura del nuovo server è illustrata in \figref{fig:TCP_echo_multiplex},
+in questo caso avremo un solo processo che ad ogni nuova connessione da parte
+di un client sul socket in ascolto si limiterà a registrare l'entrata in uso
+di un nuovo file descriptor ed utilizzerà \func{select} per rilevare la
+presenza di dati in arrivo su tutti i file descriptor attivi, operando
+direttamente su ciascuno di essi.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=13cm]{img/TCPechoMult}
+  \caption{Schema del nuovo server echo basato sull'I/O multiplexing.}
+  \label{fig:TCP_echo_multiplex}
+\end{figure}
+
+La sezione principale del codice del nuovo server è illustrata in
+\figref{fig:TCP_SelectEchod}. Si è tralasciata al solito la gestione delle
+opzioni, che è identica alla versione precedente. Resta invariata anche tutta
+la parte relativa alla gestione dei segnali, degli errori, e della cessione
+dei privilegi, così come è identica la gestione della creazione del socket (si
+può fare riferimento al codice già illustrato in
+\secref{sec:TCPsimp_server_main}); al solito il codice completo del server è
+disponibile coi sorgenti allegati nel file \texttt{select\_echod.c}.
+
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/select_echod.c}
+  \end{minipage} 
+  \normalsize
+  \caption{La sezione principale del codice della nuova versione di server
+    \textit{echo} basati sull'uso della funzione \func{select}.}
+  \label{fig:TCP_SelectEchod}
+\end{figure}
+
+In questo caso, una volta aperto e messo in ascolto il socket, tutto quello
+che ci servirà sarà chiamare \func{select} per rilevare la presenza di nuove
+connessioni o di dati in arrivo, e processarli immediatamente. Per
+implementare lo schema mostrato in \figref{fig:TCP_echo_multiplex}, il
+programma usa una tabella dei socket connessi mantenuta nel vettore
+\var{fd\_open} dimensionato al valore di \macro{FD\_SETSIZE}, ed una variabile
+\var{max\_fd} per registrare il valore più alto dei file descriptor aperti.
+
+Prima di entrare nel ciclo principale (\texttt{\small 6--56}) la nostra
+tabella viene inizializzata (\texttt{\small 2}) a zero (valore che
+utilizzeremo come indicazione del fatto che il relativo file descriptor non è
+aperto), mentre il valore massimo (\texttt{\small 3}) per i file descriptor
+aperti viene impostato a quello del socket in ascolto,\footnote{in quanto esso
+  è l'unico file aperto, oltre i tre standard, e pertanto avrà il valore più
+  alto.} che verrà anche (\texttt{\small 4}) inserito nella tabella.
+
+La prima sezione (\texttt{\small 7--10}) del ciclo principale esegue la
+costruzione del \textit{file descriptor set} \var{fset} in base ai socket
+connessi in un certo momento; all'inizio ci sarà soltanto il socket in
+ascolto, ma nel prosieguo delle operazioni, verranno utilizzati anche tutti i
+socket connessi registrati nella tabella \var{fd\_open}.  Dato che la chiamata
+di \func{select} modifica il valore del \textit{file descriptor set}, è
+necessario ripetere (\texttt{\small 7}) ogni volta il suo azzeramento, per poi
+procedere con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket
+trovati attivi.
+
+Per far questo si usa la caratteristica dei file descriptor, descritta in
+\secref{sec:file_open}, per cui il kernel associa sempre ad ogni nuovo file il
+file descriptor con il valore più basso disponibile. Questo fa sì che si possa
+eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo, che sarà
+sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, fino al
+valore massimo di \var{max\_fd} che dovremo aver cura di tenere aggiornato.
+Dopo di che basterà controllare (\texttt{\small 9}) nella nostra tabella se il
+file descriptor è in uso o meno,\footnote{si tenga presente che benché il
+  kernel assegni sempre il primo valore libero, dato che nelle operazioni i
+  socket saranno aperti e chiusi in corrispondenza della creazione e
+  conclusione delle connessioni, si potranno sempre avere dei \textsl{buchi}
+  nella nostra tabella.} e impostare \var{fset} di conseguenza.
+
+Una volta inizializzato con i socket aperti il nostro \textit{file descriptor
+  set} potremo chiamare \func{select} per fargli osservare lo stato degli
+stessi (in lettura, presumendo che la scrittura sia sempre consentita). Come
+per il precedente esempio di \secref{sec:TCP_child_hand}, essendo questa
+l'unica funzione che può bloccarsi, ed essere interrotta da un segnale, la
+eseguiremo (\texttt{\small 11--12}) all'interno di un ciclo di \code{while}
+che la ripete indefinitamente qualora esca con un errore di \errcode{EINTR}.
+Nel caso invece di un errore normale si provvede (\texttt{\small 13--16}) ad
+uscire stampando un messaggio di errore.
+
+Se invece la funzione ritorna normalmente avremo in \var{n} il numero di
+socket da controllare. Nello specifico si danno due possibili casi diversi per
+cui \func{select} può essere ritornata: o si è ricevuta una nuova connessione
+ed è pronto il socket in ascolto, sul quale si può eseguire \func{accept} o
+c'è attività su uno dei socket connessi, sui quali si può eseguire
+\func{read}.
+
+Il primo caso viene trattato immediatamente (\texttt{\small 17--26}): si
+controlla (\texttt{\small 17}) che il socket in ascolto sia fra quelli attivi,
+nel qual caso anzitutto (\texttt{\small 18}) se ne decrementa il numero in
+\var{n}; poi, inizializzata (\texttt{\small 19}) la lunghezza della struttura
+degli indirizzi, si esegue \func{accept} per ottenere il nuovo socket connesso
+controllando che non ci siano errori (\texttt{\small 20--23}). In questo caso
+non c'è più la necessità di controllare per interruzioni dovute a segnali, in
+quanto siamo sicuri che \func{accept} non si bloccherà. Per completare la
+trattazione occorre a questo punto aggiungere (\texttt{\small 24}) il nuovo
+file descriptor alla tabella di quelli connessi, ed inoltre, se è il caso,
+aggiornare (\texttt{\small 25}) il valore massimo in \var{max\_fd}.
+
+Una volta controllato l'arrivo di nuove connessioni si passa a verificare se
+vi sono dati sui socket connessi, per questo si ripete un ciclo
+(\texttt{\small 29--55}) fintanto che il numero di socket attivi \var{n} resta
+diverso da zero; in questo modo se l'unico socket con attività era quello
+connesso, avendo opportunamente decrementato il contatore, il ciclo verrà
+saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del file
+descriptor set con i nuovi valori nella tabella) alla chiamata di
+\func{accept}. Se il socket attivo non è quello in ascolto, o ce ne sono
+comunque anche altri, il valore di \var{n} non sarà nullo ed il controllo sarà
+eseguito. Prima di entrare nel ciclo comunque si inizializza (\texttt{\small
+  28}) il valore della variabile \var{i} che useremo come indice nella tabella
+\var{fd\_open} al valore minimo, corrispondente al file descriptor del socket
+in ascolto.
+
+Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore
+dell'indice \var{i} per posizionarsi sul primo valore possibile per un file
+descriptor associato ad un eventuale socket connesso, dopo di che si controlla
+(\texttt{\small 31}) se questo è nella tabella dei socket connessi, chiedendo
+la ripetizione del ciclo in caso contrario. Altrimenti si passa a verificare
+(\texttt{\small 32}) se il file descriptor corrisponde ad uno di quelli
+attivi, e nel caso si esegue (\texttt{\small 33}) una lettura, uscendo con un
+messaggio in caso di errore (\texttt{\small 34--38}).
+
+Se (\texttt{\small 39}) il numero di byte letti \var{nread} è nullo si è in
+presenza del caso di un \textit{end-of-file}, indice che una connessione che
+si è chiusa, che deve essere trattato (\texttt{\small 39--48}) opportunamente.
+Il primo passo è chiudere (\texttt{\small 40}) anche il proprio capo del
+socket e rimuovere (\texttt{\small 41}) il file descriptor dalla tabella di
+quelli aperti, inoltre occorre verificare (\texttt{\small 42}) se il file
+descriptor chiuso è quello con il valore più alto, nel qual caso occorre
+trovare (\texttt{\small 42--46}) il nuovo massimo, altrimenti (\texttt{\small
+  47}) si può ripetere il ciclo da capo per esaminare (se ne restano)
+ulteriori file descriptor attivi.
+
+Se però è stato chiuso il file descriptor più alto, dato che la scansione dei
+file descriptor attivi viene fatta a partire dal valore più basso, questo
+significa che siamo anche arrivati alla fine della scansione, per questo
+possiamo utilizzare direttamente il valore dell'indice \var{i} con un ciclo
+all'indietro (\texttt{\small 43}) che trova il primo valore per cui la tabella
+presenta un file descriptor aperto, e lo imposta (\texttt{\small 44}) come
+nuovo massimo, per poi tornare (\texttt{\small 44}) al ciclo principale con un
+\code{break}, e rieseguire \func{select}.
+
+Se infine si sono effettivamente letti dei dati dal socket (ultimo caso
+rimasto) si potrà invocare immediatamente (\texttt{\small 49})
+\func{FullWrite} per riscriverli indietro sul socket stesso, avendo cura di
+uscire con un messaggio in caso di errore (\texttt{\small 50--53}). Si noti
+che nel ciclo si esegue una sola lettura, contrariamente a quanto fatto con la
+precedente versione (si riveda il codice di \secref{fig:TCP_ServEcho_second})
+in cui si continuava a leggere fintanto che non si riceveva un
+\textit{end-of-file}, questo perché usando l'\textit{I/O multiplexing} non si
+vuole essere bloccati in lettura.  L'uso di \func{select} ci permette di
+trattare automaticamente anche il caso in cui la \func{read} non è stata in
+grado di leggere tutti i dati presenti sul socket, dato che alla iterazione
+successiva \func{select} ritornerà immediatamente segnalando l'ulteriore
+disponibilità.
+
+Il nostro server comunque soffre di una vulnerabilità per un attacco di tipo
+\textit{Denial of Service}. Il problema è che in caso di blocco di una
+qualunque delle funzioni di I/O, non avendo usato processi separati, tutto il
+server si ferma e non risponde più a nessuna richiesta. Abbiamo scongiurato
+questa evenienza per l'I/O in ingresso con l'uso di \func{select}, ma non vale
+altrettanto per l'I/O in uscita. Il problema pertanto può sorgere qualora una
+delle chiamate a \func{write} effettuate da \func{FullWrite} si blocchi. Con
+il funzionamento normale questo non accade in quanto il server si limita a
+scrivere quanto riceve in ingresso, ma qualora venga utilizzato un client
+malevolo che esegua solo scritture e non legga mai indietro l'\textsl{eco} del
+server, si potrebbe giungere alla saturazione del buffer di scrittura, ed al
+conseguente blocco del server su di una \func{write}.
+
+Le possibili soluzioni in questo caso sono quelle di ritornare ad eseguire il
+ciclo di risposta alle richieste all'interno di processi separati, utilizzare
+un timeout per le operazioni di scrittura, o eseguire queste ultime in
+modalità non bloccante, concludendo le operazioni qualora non vadano a buon
+fine.
+
+
+
+\subsection{I/O multiplexing con \func{poll}}
+\label{sec:TCP_serv_poll}
+
+Finora abbiamo trattato le problematiche risolubili con l'I/O multiplexing
+impiegando la funzione \func{select}; questo è quello che avviene nella
+maggior parte dei casi, in quanto essa è nata sotto BSD proprio per affrontare
+queste problematiche con i socket.  Abbiamo però visto in
+\secref{sec:file_multiplexing} come la funzione \func{poll} possa costituire
+una alternativa a \func{select}, con alcuni vantaggi.\footnote{non soffrendo
+  delle limitazioni dovute all'uso dei \textit{file descriptor set}.}
+
+Ancora una volta in \secref{sec:file_poll} abbiamo trattato la funzione in
+maniera generica, parlando di file descriptor, ma come per \func{select}
+quando si ha a che fare con dei socket il concetto di essere \textsl{pronti}
+per l'I/O deve essere specificato nei dettagli, per tener conto delle
+condizioni della rete. Inoltre deve essere specificato come viene classificato
+il traffico nella suddivisione fra dati normali e prioritari. In generale
+pertanto:
+\begin{itemize}
+\item i dati trasmessi su un socket vengono considerati traffico normale,
+  pertanto vengono rilevati da una selezione con \const{POLLIN} o
+  \const{POLLRDNORM}.
+\item i dati \textit{out-of-band} su un socket TCP vengono considerati
+  traffico prioritario e vengono rilevati da una condizione \const{POLLIN},
+  \const{POLLPRI} o \const{POLLRDBAND}.
+\item la chiusura di una connessione (cioè la ricezione di un segmento FIN)
+  viene considerato traffico normale, pertanto viene rilevato da una
+  condizione \const{POLLIN} o \const{POLLRDNORM}, ma una conseguente chiamata
+  a \func{read} restituirà 0.
+\item la presenza di un errore sul socket (sia dovuta ad un segmento RST che a
+  timeout) viene considerata traffico normale, ma viene segnalata anche dalla
+  condizione \const{POLLERR}.
+\item la presenza di una nuova connessione su un socket in ascolto può essere
+  considerata sia traffico normale che prioritario, nel caso di Linux
+  l'implementazione la classifica come normale.
+\end{itemize}
+
+Come esempio dell'uso di \func{poll} proviamo allora a reimplementare il
+server \textit{echo} secondo lo schema di \figref{fig:TCP_echo_multiplex}
+usando \func{poll} al posto di \func{select}. In questo caso dovremo fare
+qualche modifica, per tenere conto della diversa sintassi delle due funzioni,
+ma la struttura del programma resta sostanzialmente la stessa.
+
+
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/poll_echod.c}
+  \end{minipage} 
+  \normalsize
+  \caption{La sezione principale del codice della nuova versione di server
+    \textit{echo} basati sull'uso della funzione \func{poll}.}
+  \label{fig:TCP_PollEchod}
+\end{figure}
 
+In \figref{fig:TCP_PollEchod} è riportata la sezione principale della nuova
+versione del server, la versione completa del codice è riportata nel file
+\file{poll\_echod.c} dei sorgenti allegati alla guida. Al solito nella figura
+si sono tralasciate la gestione delle opzioni, la creazione del socket in
+ascolto, la cessione dei privilegi e le operazioni necessarie a far funzionare
+il programma come demone, privilegiando la sezione principale del programma.
+
+Come per il precedente server basato su \func{select} il primo passo
+(\texttt{\small 2--8}) è quello di inizializzare le variabili necessarie. Dato
+che in questo caso dovremo usare un vettore di strutture occorre anzitutto
+(\texttt{\small 2}) allocare la memoria necessaria utilizzando il numero
+massimo \var{n} di socket osservabili, che viene impostato attraverso
+l'opzione \texttt{-n} ed ha un valore di default di 256. 
+
+Dopo di che si preimposta (\texttt{\small 3}) il valore \var{max\_fd} del file
+descriptor aperto con valore più alto a quello del socket in ascolto (al
+momento l'unico), e si provvede (\texttt{\small 4--7}) ad inizializzare le
+strutture, disabilitando (\texttt{\small 5}) l'osservazione con un valore
+negativo del campo \var{fd} ma predisponendo (\texttt{\small 6}) il campo
+\var{events} per l'osservazione dei dati normali con \const{POLLRDNORM}.
+Infine (\texttt{\small 8}) si attiva l'osservazione del socket in ascolto
+inizializzando la corrispondente struttura. Questo metodo comporta, in
+modalità interattiva, lo spreco di tre strutture (quelle relative a standard
+input, output ed error) che non vengono mai utilizzate in quanto la prima è
+sempre quella relativa al socket in ascolto.
+
+Una volta completata l'inizializzazione tutto il lavoro viene svolto
+all'interno del ciclo principale \texttt{\small 10--55}) che ha una struttura
+sostanzialmente identica a quello usato per il precedente esempio basato su
+\func{select}. La prima istruzione (\texttt{\small 11--12}) è quella di
+eseguire \func{poll} all'interno di un ciclo che la ripete qualora venisse
+interrotta da un segnale, da cui si esce soltanto quando la funzione ritorna,
+restituendo nella variabile \var{n} il numero di file descriptor trovati
+attivi.  Qualora invece si sia ottenuto un errore si procede (\texttt{\small
+  13--16}) alla terminazione immediata del processo provvedendo a stampare una
+descrizione dello stesso.
+
+Una volta ottenuta dell'attività su un file descriptor si hanno di nuovo due
+possibilità. La prima possibilità è che ci sia attività sul socket in ascolto,
+indice di una nuova connessione, nel qual caso si controlla (\texttt{\small
+  17}) se il campo \var{revents} della relativa struttura è attivo; se è così
+si provvede (\texttt{\small 18}) a decrementare la variabile \var{n} (che
+assume il significato di numero di file descriptor attivi rimasti da
+controllare) per poi (\texttt{\small 19--23}) effettuare la chiamata ad
+\func{accept}, terminando il processo in caso di errore. Se la chiamata ad
+\func{accept} ha successo si procede attivando (\texttt{\small 24}) la
+struttura relativa al nuovo file descriptor da essa ottenuto, modificando
+(\texttt{\small 24}) infine quando necessario il valore massimo dei file
+descriptor aperti mantenuto in \var{max\_fd}.
+
+La seconda possibilità è che vi sia dell'attività su uno dei socket aperti in
+precedenza, nel qual caso si inizializza (\texttt{\small 27}) l'indice \var{i}
+del vettore delle strutture \struct{pollfd} al valore del socket in ascolto,
+dato che gli ulteriori socket aperti avranno comunque un valore superiore.  Il
+ciclo (\texttt{\small 28--54}) prosegue fintanto che il numero di file
+descriptor attivi, mantenuto nella variabile \var{n}, è diverso da zero. Se
+pertanto ci sono ancora socket attivi da individuare si comincia con
+l'incrementare (\texttt{\small 30}) l'indice e controllare (\texttt{\small
+  31}) se corrisponde ad un file descriptor in uso analizzando il valore del
+campo \var{fd} della relativa struttura e chiudendo immediatamente il ciclo
+qualora non lo sia. Se invece il file descriptor è in uso si verifica
+(\texttt{\small 31}) se c'è stata attività controllando il campo
+\var{revents}. 
+
+Di nuovo se non si verifica la presenza di attività il ciclo si chiude subito,
+altrimenti si provvederà (\texttt{\small 32}) a decrementare il numero \var{n}
+di file descriptor attivi da controllare e ad eseguire (\texttt{\small 33}) la
+lettura, ed in caso di errore (\texttt{\small 34--37}) al solito lo si
+notificherà uscendo immediatamente. Qualora invece si ottenga una condizione
+di end-of-file (\texttt{\small 38--47}) si provvederà a chiudere
+(\texttt{\small 39}) anche il nostro capo del socket e a marcarlo
+(\texttt{\small 40}) nella struttura ad esso associata come inutilizzato.
+Infine dovrà essere ricalcolato (\texttt{\small 41--45}) un eventiale nuovo
+valore di \var{max\_fd}. L'ultimo passo è (\texttt{\small 46}) chiudere il
+ciclo in quanto in questo caso non c'è più niente da riscrivere all'indietro
+sul socket.
+
+Se invece si sono letti dei dati si provvede (\texttt{\small 48}) ad
+effettuarne la riscrittura all'indietro, con il solito controllo ed eventuale
+uscita e notifica in caso si errore (\texttt{\small 49--52}).
+
+Come si può notare la logica del programma è identica a quella vista in
+\figref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la
+sola differenza significativa è che in questo caso non c'è bisogno di
+rigenerare i file descriptor set in quanto l'uscita è indipendente dai dati in
+ingresso. 
 
 
 \section{Le opzioni dei socket}