%% tcpsock.tex
%%
-%% Copyright (C) 2000-2012 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2015 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 "Un preambolo",
sez.~\ref{sec:sock_tcp_udp_options}).
\item \textit{window scale option}, il protocollo TCP implementa il controllo
- di flusso attraverso una \itindex{advertised~window} \textit{advertised
- window} (la ``\textsl{finestra annunciata}'', vedi
- sez.~\ref{sec:tcp_protocol_xxx}) con la quale ciascun capo della
- comunicazione dichiara quanto spazio disponibile ha in memoria per i dati.
- Questo è un numero a 16 bit dell'header, che così può indicare un massimo di
- 65535 byte;\footnote{in Linux il massimo è 32767 per evitare problemi con
- alcune implementazioni che usano l'aritmetica con segno per implementare
- lo stack TCP.} ma alcuni tipi di connessione come quelle ad alta velocità
- (sopra i 45Mbit/sec) e quelle che hanno grandi ritardi nel cammino dei
- pacchetti (come i satelliti) richiedono una finestra più grande per poter
- ottenere il massimo dalla trasmissione. Per questo esiste questa opzione che
- indica un fattore di scala da applicare al valore della
- \itindex{advertised~window} finestra annunciata\footnote{essendo una nuova
- opzione per garantire la compatibilità con delle vecchie implementazioni
- del protocollo la procedura che la attiva prevede come negoziazione che
- l'altro capo della connessione riconosca esplicitamente l'opzione
- inserendola anche lui nel suo SYN di risposta dell'apertura della
- connessione.} per la connessione corrente (espresso come numero di bit cui
- spostare a sinistra il valore della finestra annunciata inserito nel
- pacchetto). Con Linux è possibile indicare al kernel di far negoziare il
- fattore di scala in fase di creazione di una connessione tramite la
- \textit{sysctl} \itindex{TCP~window~scaling} \texttt{tcp\_window\_scaling}
- (vedi sez.~\ref{sec:sock_ipv4_sysctl}).\footnote{per poter usare questa
+ di flusso attraverso una \textit{advertised window} (la ``\textsl{finestra
+ annunciata}'', vedi sez.~\ref{sec:tcp_protocol_xxx}) con la quale ciascun
+ capo della comunicazione dichiara quanto spazio disponibile ha in memoria
+ per i dati. Questo è un numero a 16 bit dell'header, che così può indicare
+ un massimo di 65535 byte;\footnote{in Linux il massimo è 32767 per evitare
+ problemi con alcune implementazioni che usano l'aritmetica con segno per
+ implementare lo stack TCP.} ma alcuni tipi di connessione come quelle ad
+ alta velocità (sopra i 45Mbit/sec) e quelle che hanno grandi ritardi nel
+ cammino dei pacchetti (come i satelliti) richiedono una finestra più grande
+ per poter ottenere il massimo dalla trasmissione. Per questo esiste questa
+ opzione che indica un fattore di scala da applicare al valore della finestra
+ annunciata\footnote{essendo una nuova opzione per garantire la compatibilità
+ con delle vecchie implementazioni del protocollo la procedura che la
+ attiva prevede come negoziazione che l'altro capo della connessione
+ riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di
+ risposta dell'apertura della connessione.} per la connessione corrente
+ (espresso come numero di bit cui spostare a sinistra il valore della
+ finestra annunciata inserito nel pacchetto). Con Linux è possibile indicare
+ al kernel di far negoziare il fattore di scala in fase di creazione di una
+ connessione tramite la \textit{sysctl} \itindex{TCP~window~scaling}
+ \texttt{tcp\_window\_scaling} (vedi
+ sez.~\ref{sec:sock_ipv4_sysctl}).\footnote{per poter usare questa
funzionalità è comunque necessario ampliare le dimensioni dei buffer di
ricezione e spedizione, cosa che può essere fatta sia a livello di sistema
con le opportune \textit{sysctl} (vedi sez.~\ref{sec:sock_ipv4_sysctl})
Un'altra differenza con BSD è che la funzione non fa ereditare al nuovo socket
i flag del socket originale, come \const{O\_NONBLOCK},\footnote{ed in generale
tutti quelli che si possono impostare con \func{fcntl}, vedi
- sez.~\ref{sec:file_fcntl}.} che devono essere rispecificati ogni volta. Tutto
-questo deve essere tenuto in conto se si devono scrivere programmi portabili.
+ sez.~\ref{sec:file_fcntl_ioctl}.} che devono essere rispecificati ogni
+volta. Tutto questo deve essere tenuto in conto se si devono scrivere
+programmi portabili.
Il meccanismo di funzionamento di \func{accept} è essenziale per capire il
funzionamento di un server: in generale infatti c'è sempre un solo socket in
di riferimenti, per cui se più di un processo ha lo stesso socket aperto
l'emissione del FIN e la sequenza di chiusura di TCP non viene innescata
fintanto che il numero di riferimenti non si annulla, questo si applica, come
-visto in sez.~\ref{sec:file_sharing}, sia ai file descriptor duplicati che a
-quelli ereditati dagli eventuali processi figli, ed è il comportamento che ci
-si aspetta in una qualunque applicazione client/server.
+visto in sez.~\ref{sec:file_shared_access}, sia ai file descriptor duplicati
+che a quelli ereditati dagli eventuali processi figli, ed è il comportamento
+che ci si aspetta in una qualunque applicazione client/server.
Per attivare immediatamente l'emissione del FIN e la sequenza di chiusura
descritta in sez.~\ref{sec:TCP_conn_term}, si può invece usare la funzione
Come si può notare le due funzioni ripetono la lettura/scrittura in un ciclo
fino all'esaurimento del numero di byte richiesti, in caso di errore viene
-controllato se questo è \errcode{EINTR} (cioè un'interruzione della system
-call dovuta ad un segnale), nel qual caso l'accesso viene ripetuto, altrimenti
-l'errore viene ritornato al programma chiamante, interrompendo il ciclo.
+controllato se questo è \errcode{EINTR} (cioè un'interruzione della
+\textit{system call} dovuta ad un segnale), nel qual caso l'accesso viene
+ripetuto, altrimenti l'errore viene ritornato al programma chiamante,
+interrompendo il ciclo.
Nel caso della lettura, se il numero di byte letti è zero, significa che si è
arrivati alla fine del file (per i socket questo significa in genere che
inizializzare tutto a zero, per poi inserire il tipo di indirizzo
(\texttt{\small 21}) e la porta (\texttt{\small 22}), usando per quest'ultima
la funzione \func{htons} per convertire il formato dell'intero usato dal
-computer a quello usato nella rete, infine \texttt{\small 23--27} si può
+computer a quello usato nella rete, infine (\texttt{\small 23--27}) si può
utilizzare la funzione \func{inet\_pton} per convertire l'indirizzo numerico
passato dalla linea di comando.
In questo modo però si introduce un altro problema. Si ricordi infatti che,
come spiegato in sez.~\ref{sec:sig_gen_beha}, quando un programma si trova in
-stato di \texttt{sleep} durante l'esecuzione di una system call, questa viene
-interrotta alla ricezione di un segnale. Per questo motivo, alla fine
-dell'esecuzione del gestore del segnale, se questo ritorna, il programma
-riprenderà l'esecuzione ritornando dalla system call interrotta con un errore
-di \errcode{EINTR}.
+stato di \texttt{sleep} durante l'esecuzione di una \textit{system call},
+questa viene interrotta alla ricezione di un segnale. Per questo motivo, alla
+fine dell'esecuzione del gestore del segnale, se questo ritorna, il programma
+riprenderà l'esecuzione ritornando dalla \textit{system call} interrotta con
+un errore di \errcode{EINTR}.
Vediamo allora cosa comporta tutto questo nel nostro caso: quando si chiude il
client, il processo figlio che gestisce la connessione terminerà, ed il padre,
\end{verbatim}%#
Come accennato in sez.~\ref{sec:sig_gen_beha} le conseguenze di questo
-comportamento delle system call possono essere superate in due modi diversi,
-il più semplice è quello di modificare il codice di \func{Signal} per
-richiedere il riavvio automatico delle system call interrotte secondo la
-semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction};
-rispetto a quanto visto in fig.~\ref{fig:sig_Signal_code}. Definiremo allora la
-nuova funzione \func{SignalRestart}\footnote{anche questa è definita, insieme
- alle altre funzioni riguardanti la gestione dei segnali, nel file
+comportamento delle \textit{system call} possono essere superate in due modi
+diversi, il più semplice è quello di modificare il codice di \func{Signal} per
+richiedere il riavvio automatico delle \textit{system call} interrotte secondo
+la semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction};
+rispetto a quanto visto in fig.~\ref{fig:sig_Signal_code}. Definiremo allora
+la nuova funzione \func{SignalRestart}\footnote{anche questa è definita,
+ insieme alle altre funzioni riguardanti la gestione dei segnali, nel file
\file{SigHand.c}, il cui contento completo può essere trovato negli esempi
allegati.} come mostrato in fig.~\ref{fig:sig_SignalRestart_code}, ed
installeremo il gestore usando quest'ultima.
\end{minipage}
\normalsize
\caption{La funzione \func{SignalRestart}, che installa un gestore di
- segnali in semantica BSD per il riavvio automatico delle system call
- interrotte.}
+ segnali in semantica BSD per il riavvio automatico delle \textit{system
+ call} interrotte.}
\label{fig:sig_SignalRestart_code}
\end{figure}
Come si può notare questa funzione è identica alla precedente \func{Signal},
-illustrata in fig.~\ref{fig:sig_Signal_code}, solo che in questo caso invece di
-inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si
+illustrata in fig.~\ref{fig:sig_Signal_code}, solo che in questo caso invece
+di inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si
inizializza (\texttt{\small 5}) al valore \const{SA\_RESTART}. Usando questa
funzione al posto di \func{Signal} nel server non è necessaria nessuna altra
-modifica: le system call interrotte saranno automaticamente riavviate, e
-l'errore \errcode{EINTR} non si manifesterà più.
+modifica: le \textit{system call} interrotte saranno automaticamente
+riavviate, e l'errore \errcode{EINTR} non si manifesterà più.
La seconda soluzione è più invasiva e richiede di controllare tutte le volte
-l'errore restituito dalle varie system call, ripetendo la chiamata qualora
-questo corrisponda ad \errcode{EINTR}. Questa soluzione ha però il pregio
-della portabilità, infatti lo standard POSIX dice che la funzionalità di
-riavvio automatico delle system call, fornita da \const{SA\_RESTART}, è
-opzionale, per cui non è detto che essa sia disponibile su qualunque sistema.
-Inoltre in certi casi,\footnote{Stevens in \cite{UNP1} accenna che la maggior
- parte degli Unix derivati da BSD non fanno ripartire \func{select}; altri
- non riavviano neanche \func{accept} e \func{recvfrom}, cosa che invece nel
- caso di Linux viene sempre fatta.} anche quando questa è presente, non è
-detto possa essere usata con \func{accept}.
+l'errore restituito dalle varie \textit{system call}, ripetendo la chiamata
+qualora questo corrisponda ad \errcode{EINTR}. Questa soluzione ha però il
+pregio della portabilità, infatti lo standard POSIX dice che la funzionalità
+di riavvio automatico delle \textit{system call}, fornita da
+\const{SA\_RESTART}, è opzionale, per cui non è detto che essa sia disponibile
+su qualunque sistema. Inoltre in certi casi,\footnote{Stevens in \cite{UNP1}
+ accenna che la maggior parte degli Unix derivati da BSD non fanno ripartire
+ \func{select}; altri non riavviano neanche \func{accept} e \func{recvfrom},
+ cosa che invece nel caso di Linux viene sempre fatta.} anche quando questa è
+presente, non è detto possa essere usata con \func{accept}.
La portabilità nella gestione dei segnali però viene al costo di una
\normalsize
\caption{La sezione nel codice della seconda versione del server
per il servizio \textit{echo} modificata per tener conto dell'interruzione
- delle system call.}
+ delle \textit{system call}.}
\label{fig:TCP_echo_server_code_second}
\end{figure}
numero di secondi da aspettare (il valore preimpostato è nullo).
Si è potuto lasciare inalterata tutta la sezione di creazione del socket
-perché nel server l'unica chiamata ad una system call lenta, che può essere
-interrotta dall'arrivo di \signal{SIGCHLD}, è quella ad \func{accept}, che è
-l'unica funzione che può mettere il processo padre in stato di sleep nel
+perché nel server l'unica chiamata ad una \textit{system call} lenta, che può
+essere interrotta dall'arrivo di \signal{SIGCHLD}, è quella ad \func{accept},
+che è l'unica funzione che può mettere il processo padre in stato di sleep nel
periodo in cui un figlio può terminare; si noti infatti come le altre
-\index{system~call~lente} \textit{slow system call}\footnote{si ricordi la
- distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di
+\index{system~call~lente} \textit{system call} lente (si ricordi la
+distinzione fatta in sez.~\ref{sec:sig_gen_beha}) o sono chiamate prima di
entrare nel ciclo principale, quando ancora non esistono processi figli, o
sono chiamate dai figli stessi e non risentono di \signal{SIGCHLD}.
sempre attivo il campo \texttt{ack}, seguito dal numero di sequenza per il
quale si da il ricevuto; quest'ultimo, a partire dal terzo pacchetto, viene
espresso in forma relativa per maggiore compattezza. Il campo \texttt{win} in
-ogni riga indica la \itindex{advertised~window} \textit{advertised window} di
-cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può verificare
-dall'output del comando come venga appunto realizzata la sequenza di pacchetti
-descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un
-primo pacchetto con il SYN che inizia la connessione, a cui il server risponde
-dando il ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui
-il client risponde con un il terzo pacchetto di ricevuto.
+ogni riga indica la \textit{advertised window} di cui parlavamo in
+sez.~\ref{sec:TCP_TCP_opt}. Allora si può verificare dall'output del comando
+come venga appunto realizzata la sequenza di pacchetti descritta in
+sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un primo pacchetto
+con il SYN che inizia la connessione, a cui il server risponde dando il
+ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui il client
+risponde con un il terzo pacchetto di ricevuto.
Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe
del \itindex{three~way~handshake} \textit{three way handshake} non avremo
è una operazione lecita, per cui la nostra scrittura avrà comunque successo
(come si può constatare lanciando usando \cmd{strace}\footnote{il comando
\cmd{strace} è un comando di debug molto utile che prende come argomento un
- altro comando e ne stampa a video tutte le invocazioni di una system call,
- coi relativi argomenti e valori di ritorno, per cui usandolo in questo
- contesto potremo verificare che effettivamente la \func{write} ha scritto la
- riga, che in effetti è stata pure trasmessa via rete.}), in quanto il nostro
-programma non ha a questo punto alcun modo di sapere che dall'altra parte non
-c'è più nessuno processo in grado di leggere quanto scriverà. Questo sarà
-chiaro solo dopo il tentativo di scrittura, e la ricezione del segmento RST di
-risposta che indica che dall'altra parte non si è semplicemente chiuso un capo
-del socket, ma è completamente terminato il programma.
+ altro comando e ne stampa a video tutte le invocazioni di una \textit{system
+ call}, coi relativi argomenti e valori di ritorno, per cui usandolo in
+ questo contesto potremo verificare che effettivamente la \func{write} ha
+ scritto la riga, che in effetti è stata pure trasmessa via rete.}), in
+quanto il nostro programma non ha a questo punto alcun modo di sapere che
+dall'altra parte non c'è più nessuno processo in grado di leggere quanto
+scriverà. Questo sarà chiaro solo dopo il tentativo di scrittura, e la
+ricezione del segmento RST di risposta che indica che dall'altra parte non si
+è semplicemente chiuso un capo del socket, ma è completamente terminato il
+programma.
Per questo motivo il nostro client proseguirà leggendo dal socket, e dato che
questo è stato chiuso avremo che, come spiegato in