%% 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
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Prefazione",
%% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
\chapter{Socket TCP avanzati}
\label{cha:TCP_advanced}

Esamineremo in questo capitolo le funzionalità più evolute della gestione dei
socket TCP, come l'uso del I/O multiplexing (trattato in
\secref{sec:file_multiplexing}) con i socket, l'uso delle opzioni dei socket e
la gestione dei dati urgenti e \textit{out-of-band}.



\section{Socket I/O multiplexing}
\label{sec:TCP_sock_multiplexing}

Affronteremo in questa sezione l'utilizzo dell'I/O multiplexing, affrontato in
\secref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già in
\secref{sec:TCP_server_crash} era emerso il problema relativo al client del
servizio echo che non era in grado di accorgersi della terminazione precoce
del server, essendo bloccato nella lettura dei dati immessi da tastiera.

Abbiamo visto in \secref{sec:file_multiplexing} quali sono le funzionalità del
sistema che ci permettono di tenere sotto controllo più file descriptor in
contemporanea; in quella occasione non abbiamo fatto esempi, in quanto quando
si tratta con file normali questa tipologia di I/O normalmente non viene
usata, è invece un caso tipico delle applicazioni di rete quello di dover
gestire varie connessioni da cui possono arrivare dati comuni in maniera
asincrona, per cui riprenderemo l'argomento in questa sezione.


\subsection{Il comportamento della funzione \func{select} con i socket.}
\label{sec:TCP_sock_select}

Iniziamo con la prima delle funzioni usate per l'I/O multiplexing,
\func{select}; il suo funzionamento è già stato descritto in dettaglio in
\secref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì; 
sappiamo che la funzione ritorna quando uno o più dei file descriptor messi
sotto controllo è pronto per la relativa operazione.

In quell'occasione non abbiamo però definito cosa si intende per pronto,
infatti per dei normali file, o anche per delle pipe, la condizione di essere
pronti per la lettura o la scrittura è ovvia; invece lo è molto meno nel caso
dei socket, visto che possono intervenire tutte una serie di possibili
condizioni di errore dovute alla rete. Occorre allora specificare chiaramente
quali sono le condizioni per cui un socket risulta essere ``\textsl{pronto}''
quando viene passato come membro di uno dei tre \textit{file descriptor set}
usati da \func{select}.

Le condizioni che fanno si che la funzione \func{select} ritorni segnalando
che un socket (che sarà riportato nel primo insieme di file descriptor) è
pronto per la lettura sono le seguenti:
\begin{itemize*}
\item nel buffer di ricezione del socket sono arrivati dei dati in quantità
  sufficiente a superare il valore di una \textsl{soglia di basso livello} (il
  cosiddetto \textit{low watermark}). Questo valore è espresso in numero di
  byte e può essere impostato con l'opzione del socket \const{SO\_RCVLOWAT}
  (tratteremo le opzioni dei socket in \secref{sec:TCP_sock_options}); il suo
  valore di default è 1 per i socket TCP e UDP. In questo caso una operazione
  di lettura avrà successo e leggerà un numero di byte maggiore di zero.
\item il lato in lettura della connessione è stato chiuso; si è cioè ricevuto
  un segmento FIN (si ricordi quanto illustrato in \secref{sec:TCP_conn_term})
  sulla connessione. In questo caso una operazione di lettura avrà successo,
  ma non risulteranno presenti dati (in sostanza \func{read} ritornerà con un
  valore nullo) per indicare la condizione di end-of-file.
\item c'è stato un errore sul socket. In questo caso una operazione di lettura
  non si bloccherà ma restituirà una condizione di errore (ad esempio
  \func{read} restituirà -1) e imposterà la variabile \var{errno} al relativo
  valore. Vedremo in \secref{sec:TCP_sock_options} come sia possibile estrarre
  e cancellare errori pendenti su un socket usando l'opzione
  \const{SO\_ERROR}.
\item quando si sta utilizzando un \textit{listening socket} ed ci sono delle
  connessioni completate. In questo caso la funzione \func{accept} non si
  bloccherà.\footnote{in realtà questo non è sempre vero, come accennato in
    \secref{sec:TCP_conn_early_abort} una connessione può essere abortita
    dalla ricezione di un segmento RST una volta che è stata completata,
    allora se questo avviene dopo che \func{select} è ritornata, ma prima
    della chiamata ad \func{accept}, quest'ultima, in assenza di altre
    connessioni, potrà bloccarsi.}
\end{itemize*}

Le condizioni che fanno si che la funzione \func{select} ritorni segnalando
che un socket (che sarà riportato nel secondo insieme di file descriptor) è
pronto per la scrittura sono le seguenti:
\begin{itemize*}
\item nel buffer di invio è disponibile una quantità di spazio superiore al
  valore della \textsl{soglia di basso livello} in scrittura ed inoltre o il
  socket è già connesso o non necessita (ad esempio è UDP) di connessione.  Il
  valore della soglia è espresso in numero di byte e può essere impostato con
  l'opzione del socket \const{SO\_SNDLOWAT}; il suo valore di default è 2048
  per i socket TCP e UDP. In questo caso una operazione di scrittura non si
  bloccherà e restituirà un valore positivo pari al numero di byte accettati
  dal livello di trasporto.
\item il lato in scrittura della connessione è stato chiuso. In questo caso
  una operazione di scrittura sul socket genererà il segnale \const{SIGPIPE}.
\item c'è stato un errore sul socket. In questo caso una operazione di
  scrittura non si bloccherà ma restituirà una condizione di errore ed
  imposterà opportunamente la variabile \var{errno}. Vedremo in
  \secref{sec:TCP_sock_options} come sia possibile estrarre e cancellare
  errori pendenti su un socket usando l'opzione \const{SO\_ERROR}.
\end{itemize*}

Infine c'è una sola condizione che fa si che \func{select} ritorni segnalando
che un socket (che sarà riportato nel terzo insieme di file descriptor) ha una
condizione di eccezione pendente, e cioè la ricezione sul socket di dati
\textsl{fuori banda} (o \textit{out-of-band}), una caratteristica specifica
dei socket TCP su cui torneremo in \secref{sec:TCP_urgent_data}.

Si noti come nel caso della lettura \func{select} si applichi anche ad
operazioni che non hanno nulla a che fare con l'I/O di dati come il
riconoscimento della presenza di connessioni pronte, in modo da consentire
anche l'utilizzo di \func{accept} in modalità non bloccante. Si noti infine
come in caso di errore un socket venga sempre riportato come pronto sia per la
lettura che per la scrittura.

Lo scopo dei due valori di soglia per i buffer di ricezione e di invio è
quello di consentire maggiore flessibilità nell'uso di \func{select} da parte
dei programmi, se infatti si sa che una applicazione non è in grado di fare
niente fintanto che non può ricevere o inviare una certa quantità di dati, si
possono utilizzare questi valori per far si che \func{select} ritorni solo
quando c'è la certezza di avere dati a sufficienza.\footnote{questo tipo di
  controllo è utile di norma solo per la lettura, in quanto in genere le
  operazioni di scrittura sono già controllate dall'applicazione, che sà
  sempre quanti dati invia, mentre non è detto possa conoscere la quantità di
  dati in ricezione; per cui, nella situazione in cui si conosce almeno un
  valore minimo, per evitare la penalizzazione dovuta alla ripetizione delle
  operazioni di lettura per accumulare dati sufficienti, si può lasciare al
  kernel il compito di impostare un minimo al di sotto del quale il file
  descriptor, pur avendo disponibili dei dati, non viene dato per pronto in
  lettura.}



\subsection{Un esempio di I/O multiplexing}
\label{sec:TCP_multiplex_example}

Abbiamo incontrato la problematica tipica che conduce all'uso dell'I/O
multiplexing nella nostra analisi degli errori in
\secref{sec:TCP_conn_early_abort}, quando il nostro client non era in grado di
rendersi conto di errori sulla connessione essendo impegnato nella attesa di
dati in ingresso dallo standard input.

In questo caso il problema è quello di dover tenere sotto controllo due
diversi file descriptor, lo standard input, da cui viene letto il testo che
vogliamo inviare al server, e il socket connesso con il server su cui detto
testo sarà scritto e dal quale poi si vorrà ricevere la risposta. L'uso
dell'I/O multiplexing consente di tenere sotto controllo entrambi, senza
restare bloccati.

Nel nostro caso quello che ci interessa è non essere bloccati in lettura sullo
standard input in caso di errori sulla connessione o chiusura della stessa da
parte del server. Entrambi questi casi possono essere rilevati usando
\func{select}, per quanto detto in \secref{sec:TCP_sock_select}, mettendo
sotto osservazione i file descriptor per la condizione di essere pronti in
lettura: sia infatti che si ricevano dati, che la connessione sia chiusa
regolarmente (con la ricezione di un segmento FIN) che si riceva una
condizione di errore (con un segmento RST) il socket connesso sarà pronto in
lettura (nell'ultimo caso anche in scrittura, ma questo non è necessario ai
nostri scopi).

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/ClientEcho_third.c}
  \end{minipage} 
  \normalsize
  \caption{La sezione nel codice della terza versione della funzione
    \func{ClientEcho} usata dal client per il servizio \textit{echo}
    modificata per l'uso di \func{select}.}
  \label{fig:TCP_ClientEcho_third}
\end{figure}

Riprendiamo allora il codice del client, modificandolo per l'uso di
\func{select}. Quello che dobbiamo modificare è la funzione \func{ClientEcho}
di \figref{fig:TCP_ClientEcho_second}, dato che tutto il resto, che riguarda
le modalità in cui viene stabilita la connessione con il server, resta
assolutamente identico. La nostra nuova versione di \func{ClientEcho}, la
terza della serie, è riportata in \figref{fig:TCP_ClientEcho_third}, il codice
completo si trova nel file \file{TCP\_echo\_third.c} dei sorgenti allegati alla
guida.

In questo caso la funzione comincia (\texttt{\small 8--9}) con l'azzeramento
del file descriptor set \var{fset} e l'impostazione del valore \var{maxfd}, da
passare a \func{select} come massimo per il numero di file descriptor. Per
determinare quest'ultimo si usa la macro \code{max} definita nel nostro file
\file{macro.h} che raccoglie una collezione di macro di preprocessore di varia
utilità.

La funzione prosegue poi (\texttt{\small 10--41}) con il ciclo principale, che
viene ripetuto indefinitamente. Per ogni ciclo si reinizializza
(\texttt{\small 11--12}) il file descriptor set, impostando i valori per il
file descriptor associato al socket \var{socket} e per lo standard input (il
cui valore si recupera con la funzione \func{fileno}). Questo è necessario in
quanto la successiva (\texttt{\small 13}) chiamata a \func{select} comporta
una modifica dei due bit relativi, che quindi devono essere reimpostati
all'inizio di ogni ciclo.

Si noti come la chiamata a \func{select} venga eseguita usando come primo
argomento il valore di \var{maxfd}, precedentemente calcolato, e passando poi
il solo file descriptor set per il controllo dell'attività in lettura, negli
altri argomenti sono passati tutti puntatori nulli, non interessando né il
controllo delle altre attività, né l'impostazione di un valore di timeout.

Al ritorno di \func{select} si provvede a controllare quale dei due file
descriptor presenta attività in lettura, cominciando (\texttt{\small 14--24})
con il file descriptor associato allo standard input. In caso di attività
(quando cioè \macro{FD\_ISSET} ritorna una valore diverso da zero) si esegue
(\texttt{\small 15}) una \func{fgets} per leggere gli eventuali dati presenti;
se non ve ne sono (e la funzione restituisce pertanto un puntatore nullo) si
ritorna immediatamente (\texttt{\small 16}) dato che questo significa che si è
chiuso lo standard input e quindi concluso l'utilizzo del client; altrimenti
(\texttt{\small 18--22}) si scrivono i dati appena letti sul socket,
prevedendo una uscita immediata in caso di errore di scrittura.

Controllato lo standard input si passa a controllare (\texttt{\small 25--40})
il socket connesso, in caso di attività (\texttt{\small 26}) si esegue subito
una \func{read} di cui si controlla il valore di ritorno; se questo è negativo
(\texttt{\small 27--30}) si è avuto un errore e pertanto si esce
immediatamente segnalandolo, se è nullo (\texttt{\small 31--34}) significa che
il server ha chiuso la connessione, e di nuovo si esce con stampando prima un
messaggio di avviso, altrimenti (\texttt{\small 35--39}) si effettua la
terminazione della stringa e la si stampa a sullo standard output (uscendo in
caso di errore), per ripetere il ciclo da capo.

Con questo meccanismo il programma invece di essere bloccato in lettura sullo
standard input resta bloccato sulla \func{select}, che ritorna soltanto quando
viene rilevata attività su uno dei due file descriptor posti sotto controllo.
Questo di norma avviene solo quando si è scritto qualcosa sullo standard
input, o quando si riceve dal socket la risposta a quanto si era appena
scritto. Ma adesso il client diventa capace di accorgersi immediatamente della
terminazione del server; in tal caso infatti il server chiuderà il socket
connesso, ed alla ricezione del FIN la funzione \func{select} ritornerà (come
illustrato in \secref{sec:TCP_sock_select}) segnalando una condizione di end
of file, per cui il nostro client potrà uscire immediatamente.

Riprendiamo la situazione affrontata in \secref{sec:TCP_server_crash},
terminando il server durante una connessione, in questo caso quello che
otterremo, una volta scritta una prima riga ed interrotto il server con un
\texttt{C-c}, sarà:
\begin{verbatim}
[piccardi@gont sources]$ ./echo 192.168.1.1
Prima riga
Prima riga
EOF sul socket
\end{verbatim}%$
dove l'ultima riga compare immediatamente dopo aver interrotto il server. Il
nostro client infatti è in grado di accorgersi immediatamente che il socket
connesso è stato chiuso ed uscire immediatamente.

Veniamo allora agli altri scenari di terminazione anomala visti in
\secref{sec:TCP_conn_crash}. Il primo di questi è l'interruzione fisica della
connessione; in questo caso avremo un comportamento analogo al precedente, in
cui si scrive una riga e non si riceve risposta dal server e non succede
niente fino a quando non si riceve un errore di \errcode{EHOSTUNREACH} o
\errcode{ETIMEDOUT} a seconda dei casi.

La differenza è che stavolta potremo scrivere più righe dopo l'interruzione,
in quanto il nostro client dopo aver inviato i dati non si bloccherà più nella
lettura dal socket, ma nella \func{select}; per questo potrà accettare
ulteriore dati che scriverà di nuovo sul socket, fintanto che c'è spazio sul
buffer di uscita (ecceduto il quale si bloccherà in scrittura). Si ricordi
infatti che il client non ha modo di determinare se la connessione è attiva o
meno (dato che in molte situazioni reali l'inattività può essere temporanea).
Tra l'altro se si ricollega la rete prima della scadenza del timeout, potremo
anche verificare come tutto quello che si era scritto viene poi effettivamente
trasmesso non appena la connessione ridiventa attiva, per cui otterremo
qualcosa del tipo:
\begin{verbatim}
[piccardi@gont sources]$ ./echo 192.168.1.1
Prima riga
Prima riga
Seconda riga dopo l'interruzione
Terza riga
Quarta riga
Seconda riga dopo l'interruzione
Terza riga
Quarta riga
\end{verbatim}
in cui, una volta riconnessa la rete, tutto quello che abbiamo scritto durante
il periodo di disconnessione restituito indietro e stampato immediatamente.

Lo stesso comportamento visto in \secref{sec:TCP_server_crash} si riottiene
nel caso di un crollo completo della macchina su cui sta il server. In questo
caso di nuovo il client non è in grado di accorgersi di niente dato che si
suppone che il programma server non venga terminato correttamente, ma si
blocchi tutto senza la possibilità di avere l'emissione di un segmento FIN che
segnala la terminazione della connessione. Di nuovo fintanto che la
connessione non si riattiva )con il riavvio della macchina del server) il
client non è in grado di fare altro che accettare dell'input e tentare di
inviarlo. La differenza in questo caso è che non appena la connessione
ridiventa attiva i dati verranno sì trasmessi, ma essendo state perse tutte le
informazioni relative alle precedenti connessioni ai tentativi di scrittura
del client sarà risposto con un segmento RST che provocherà il ritorno di
\func{select} per la ricezione di un errore di \errcode{ECONNRESET}.


\subsection{La funzione \func{shutdown}}
\label{sec:TCP_shutdown}

Come spiegato in \secref{sec:TCP_conn_term} il procedimento di chiusura di un
socket TCP prevede che da entrambe le parti venga emesso un segmento FIN. È
pertanto del tutto normale dal punto di vista del protocollo che uno dei due
capi chiuda la connessione, quando l'altro capo la lascia
aperta.\footnote{abbiamo incontrato questa situazione nei vari scenari critici
  di \secref{sec:TCP_echo_critical}.}

È pertanto possibile avere una situazione in cui un capo della connessione non
avendo più nulla da scrivere, possa chiudere il socket, segnalando così
l'avvenuta terminazione della trasmissione (l'altro capo riceverà infatti un
end-of-file in lettura) mentre dall'altra parte si potrà proseguire la
trasmissione dei dati scrivendo sul socket che da quel lato è ancora aperto.
Questa è quella situazione in cui si dice che il socket è \textit{half
  closed}.

Il problema che si pone è che se la chiusura del socket è effettuata con la
funzione \func{close}, come spiegato in \secref{sec:TCP_func_close}, si perde
ogni possibilità di poter rileggere quanto l'altro capo può continuare a
scrivere. Per poter permettere allora di segnalare che si è concluso con la
scrittura, continuando al contempo a leggere quanto può provenire dall'altro
capo del socket si può allora usare la funzione \funcd{shutdown}, il cui
prototipo è:
\begin{prototype}{sys/socket.h}
{int shutdown(int sockfd, int how)}

Chiude un lato della connessione fra due socket.
  
  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
    errore, nel qual caso \var{errno} assumerà i valori:
  \begin{errlist}
  \item[\errcode{ENOTSOCK}] il file descriptor non corrisponde a un socket.
  \item[\errcode{ENOTCONN}] il socket non è connesso.
  \end{errlist}
  ed inoltre \errval{EBADF}.}
\end{prototype}

La funzione prende come primo argomento il socket \param{sockfd} su cui si
vuole operare e come secondo argomento un valore intero \param{how} che indica
la modalità di chiusura del socket, quest'ultima può prendere soltanto tre
valori: 
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\macro{SHUT\_RD}] chiude il lato in lettura del socket, non sarà più
  possibile leggere dati da esso, tutti gli eventuali dati trasmessi
  dall'altro capo del socket saranno automaticamente scartati dal kernel, che,
  in caso di socket TCP, provvederà comunque ad inviare i relativi segmenti di
  ACK.
\item[\macro{SHUT\_WR}] chiude il lato in scrittura del socket, non sarà più
  possibile scrivere dati su di esso. Nel caso di socket TCP la chiamata causa
  l'emissione di un segmento FIN, secondo la procedura chiamata
  \textit{half-close}. Tutti i dati presenti nel buffer di scrittura prima
  della chiamata saranno inviati, seguiti dalla sequenza di chiusura
  illustrata in \secref{sec:TCP_conn_term}.
\item[\macro{SHUT\_RDWR}] chiude sia il lato in lettura che quello in
  scrittura del socket. È equivalente alla chiamata in sequenza con
  \macro{SHUT\_RD} e \macro{SHUT\_WR}.
\end{basedescript}

Ci si può chiedere quale sia l'utilità di avere introdotto \macro{SHUT\_RDWR}
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
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 è
assolutamente vero, (e lo abbiamo già visto nel codice del server di
\figref{fig:TCP_echo_server_first_code}), ed è invece assolutamente normale
che, come per gli altri oggetti, ci possano essere più file descriptor che
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 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
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}%$
vedremo che il file \texttt{copia} risulta mancare della parte finale.

Per capire cosa avviene in questo caso occorre tenere presente come avviene la
comunicazione via rete; quando redirigiamo lo standard input il nostro client
inizierà a leggere il contenuto del file \texttt{../fileadv.tex} a blocchi di
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 è 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}, 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 indietro, fino a quando anch'esso,
riconosciuta la chiusura del socket in scrittura da parte del client,
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
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/ClientEcho.c}
  \end{minipage} 
  \normalsize
  \caption{La sezione nel codice della versione finale della funzione
    \func{ClientEcho}, che usa \func{shutdown} per una conclusione corretta
    della connessione.}
  \label{fig:TCP_ClientEcho}
\end{figure}

Si è allora riportato in \figref{fig:TCP_ClientEcho} la versione finale della
nostra funzione \func{ClientEcho}, in grado di gestire correttamente l'intero
flusso di dati fra client e server. Il codice completo del client,
comprendente la gestione delle opzioni a riga di comando e le istruzioni per
la creazione della connessione, si trova nel file \file{TCP\_echo.c},
distribuito coi sorgenti allegati alla guida.

La nuova versione è molto simile alla precedente di
\figref{fig:TCP_ClientEcho_third}; la prima differenza è l'introduzione
(\texttt{\small 7}) della variabile \var{eof}, inizializzata ad un valore
nullo, che serve a mantenere traccia dell'avvenuta conclusione della lettura
del file in ingresso.

La seconda modifica (\texttt{\small 12--15}) è stata quella di rendere
subordinato ad un valore nullo di \var{eof} l'impostazione del file descriptor
set per l'osservazione dello standard input. Se infatti il valore di \var{eof}
è non nullo significa che si è già raggiunta la fine del file in ingresso ed è
pertanto inutile continuare a tenere sotto controllo lo standard input nella
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}
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 output.

Il ritorno della funzione, e la conseguente terminazione normale del client,
viene invece adesso gestito all'interno (\texttt{\small 30--49}) della lettura
dei dati dal socket; se infatti dalla lettura del socket si riceve una
condizione di end-of-file, la si tratterà (\texttt{\small 36--43}) in maniera
diversa a seconda del valore di \var{eof}. Se infatti questa è diversa da zero
(\texttt{\small 37--39}), essendo stata completata la lettura del file in
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
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, cocludendo 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 esistono altre funzioni che permettono di
affrontare lo stesso problema e 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, 






\section{Le opzioni dei socket}
\label{sec:TCP_sock_options}

Dato che la maggior parte delle opzioni dei socket sono relative ai socket
TCP, ed hanno poi significato analogo quando usate con altri socket, abbiamo
preferito trattare l'argomento in generale in questa sezione piuttosto che nel
capitolo dedicato alla trattazione generica dei socket.



\section{I dati \textit{out-of-band}}
\label{sec:TCP_urgent_data}

Una caratteristica speciale dei socket TCP è quella della presenza dei
cosiddetti dati \textit{out-of-band}




%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "gapil"
%%% End: 
