\subsection{La creazione della connessione: il \textit{three way handshake}}
\label{sec:TCP_conn_cre}
-\index{\textit{three~way~handshake}|(}
+\itindbeg{three~way~handshake}
Il processo che porta a creare una connessione TCP è chiamato \textit{three
way handshake}; la successione tipica degli eventi (e dei
\textsl{segmenti}\footnote{Si ricordi che il segmento è l'unità elementare di
SYN consuma un byte, nel \textit{three way handshake} il numero di acknowledge
è sempre pari al numero di sequenza iniziale incrementato di uno; lo stesso
varrà anche (vedi fig.~\ref{fig:TCP_close}) per l'acknowledgement di un FIN.
-\index{\textit{three~way~handshake}|)}
+
+\itindend{three~way~handshake}
\subsection{Le opzioni TCP.}
connessione corrente. È possibile leggere e scrivere questo valore
attraverso l'opzione del socket \const{TCP\_MAXSEG}.
-\item \textit{window scale option}, %come spiegato in sez.~\ref{sec:tcp_protocol}
+\item \textit{window scale
+ option}, %come spiegato in sez.~\ref{sec:tcp_protocol}
il protocollo TCP implementa il controllo di flusso attraverso una
\textsl{finestra annunciata} (\textit{advertized window}) con la quale
ciascun capo della comunicazione dichiara quanto spazio disponibile ha in
instradamento dei pacchetti possono impiegare diverso tempo (anche dell'ordine
dei minuti) prima di trovare e stabilire un percorso alternativo per i
pacchetti. Nel frattempo possono accadere casi in cui un router manda i
-pacchetti verso un'altro e quest'ultimo li rispedisce indietro, o li manda ad
+pacchetti verso un altro e quest'ultimo li rispedisce indietro, o li manda ad
un terzo router che li rispedisce al primo, si creano cioè dei circoli (i
cosiddetti \textit{routing loop}) in cui restano intrappolati i pacchetti.
tcp 0 0 195.110.112.152:22 192.84.146.100:21101 ESTABLISHED
\end{verbatim}
cioè il client effettuerà la connessione usando un'altra porta effimera: con
-questa sarà aperta la connessione, ed il server creerà un'altro processo
+questa sarà aperta la connessione, ed il server creerà un altro processo
figlio per gestirla.
Tutto ciò mostra come il TCP, per poter gestire le connessioni con un server
concorrente, non può suddividere i pacchetti solo sulla base della porta di
destinazione, ma deve usare tutta l'informazione contenuta nella socket pair,
compresa la porta dell'indirizzo remoto. E se andassimo a vedere quali sono i
-processi\footnote{ad esempio con il comando \cmd{fuser}, o con \cmd{lsof}.} a
-cui fanno riferimento i vari socket vedremmo che i pacchetti che arrivano
-dalla porta remota 21100 vanno al primo figlio e quelli che arrivano alla
-porta 21101 al secondo.
+processi\footnote{ad esempio con il comando \cmd{fuser}, o con \cmd{lsof}, o
+ usando l'opzione \texttt{-p}.} a cui fanno riferimento i vari socket
+vedremmo che i pacchetti che arrivano dalla porta remota 21100 vanno al primo
+figlio e quelli che arrivano alla porta 21101 al secondo.
\section{Le funzioni di base per la gestione dei socket}
\const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è
inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_}
(riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo
-l'\textit{endianess}\index{\textit{endianess}} della macchina, ed anche se
+l'\textit{endianess}\itindex{endianess} della macchina, ed anche se
esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque
buona norma usare sempre la funzione \func{htonl}.
costante come operando a destra in una assegnazione.
Per questo motivo nell'header \file{netinet/in.h} è definita una variabile
-\const{in6addr\_any} (dichiarata come \direct{extern}, ed inizializzata dal
+\macro{in6addr\_any} (dichiarata come \direct{extern}, ed inizializzata dal
sistema al valore \const{IN6ADRR\_ANY\_INIT}) che permette di effettuare una
assegnazione del tipo: \includecodesnip{listati/serv_addr_sin6_addr.c} in
-maniera analoga si può utilizzare la variabile \const{in6addr\_loopback} per
+maniera analoga si può utilizzare la variabile \macro{in6addr\_loopback} per
indicare l'indirizzo di \textit{loopback}, che a sua volta viene inizializzata
staticamente a \const{IN6ADRR\_LOOPBACK\_INIT}.
limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati
e ricevuti i pacchetti, mentre per socket di tipo \const{SOCK\_STREAM} o
\const{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del
- TCP il \index{\textit{three~way~handshake}}\textit{three way handshake})
- della connessione.} il prototipo della funzione è il seguente:
+ TCP il \itindex{three~way~handshake}\textit{three way handshake}) della
+ connessione.} il prototipo della funzione è il seguente:
\begin{prototype}{sys/socket.h}
{int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t
addrlen)}
in sez.~\ref{sec:sock_addr_func}.
Nel caso di socket TCP la funzione \func{connect} avvia il
-\index{\textit{three~way~handshake}}\textit{three way handshake}, e ritorna
+\itindex{three~way~handshake}\textit{three way handshake}, e ritorna
solo quando la connessione è stabilita o si è verificato un errore. Le
possibili cause di errore sono molteplici (ed i relativi codici riportati
sopra), quelle che però dipendono dalla situazione della rete e non da errori
\begin{enumerate}
\item Il client non riceve risposta al SYN: l'errore restituito è
\errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla chiamata
- di \func{connect}, un'altro dopo 6 secondi, un terzo dopo 24 secondi, se
+ di \func{connect}, un altro dopo 6 secondi, un terzo dopo 24 secondi, se
dopo 75 secondi non ha ricevuto risposta viene ritornato l'errore. Linux
invece ripete l'emissione del SYN ad intervalli di 30 secondi per un numero
di volte che può essere stabilito dall'utente sia con una opportuna
voluto in \file{/proc/sys/net/ipv4/tcp\_syn\_retries}. Il valore predefinito
per la ripetizione dell'invio è di 5 volte, che comporta un timeout dopo
circa 180 secondi.
-%
-% Le informazioni su tutte le opzioni impostabili via /proc stanno in
-% Linux/Documentation/networking/ip-sysctl.txt
-%
+
\item Il client riceve come risposta al SYN un RST significa che non c'è
nessun programma in ascolto per la connessione sulla porta specificata (il
che vuol dire probabilmente che o si è sbagliato il numero della porta o che
\begin{enumerate}
\item La coda delle connessioni incomplete (\textit{incomplete connection
queue} che contiene un riferimento per ciascun socket per il quale è
- arrivato un SYN ma il \index{\textit{three~way~handshake}}\textit{three way
+ arrivato un SYN ma il \itindex{three~way~handshake}\textit{three way
handshake} non si è ancora concluso. Questi socket sono tutti nello stato
\texttt{SYN\_RECV}.
\item La coda delle connessioni complete (\textit{complete connection queue}
delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La voce resterà
nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal
client o fino ad un timeout. Nel caso di completamento del
-\index{\textit{three~way~handshake}}\textit{three way handshake} la voce viene
+\itindex{three~way~handshake}\textit{three way handshake} la voce viene
spostata nella coda delle connessioni complete. Quando il processo chiama la
funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept}) la prima voce
nella coda delle connessioni complete è passata al programma, o, se la coda è
server è occupato fra chiamate successive alla \func{accept} (per cui la coda
più occupata sarebbe quella delle connessioni completate), ma piuttosto quello
di gestire la presenza di un gran numero di SYN in attesa di concludere il
-\textit{three way handshake}\index{\textit{three~way~handshake}}.
+\textit{three way handshake}\itindex{three~way~handshake}.
Infine va messo in evidenza che, nel caso di socket TCP, quando un SYN arriva
con tutte le code piene, il pacchetto deve essere ignorato. Questo perché la
\label{sec:TCP_func_accept}
La funzione \funcd{accept} è chiamata da un server per gestire la connessione
-una volta che sia stato completato il \textit{three way
- handshake},\footnote{la funzione è comunque generica ed è utilizzabile su
- socket di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET} e
- \const{SOCK\_RDM}.} la funzione restituisce un nuovo socket descriptor su
+una volta che sia stato completato il \itindex{three~way~handshake}
+\textit{three way handshake},\footnote{la funzione è comunque generica ed è
+ utilizzabile su socket di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET}
+ e \const{SOCK\_RDM}.} la funzione restituisce un nuovo socket descriptor su
cui si potrà operare per effettuare la comunicazione. Se non ci sono
connessioni completate il processo viene messo in attesa. Il prototipo della
funzione è il seguente:
27--30}) l'operazione usando \func{setuid} per cambiare anche
l'utente.\footnote{si tenga presente che l'ordine in cui si eseguono queste
due operazioni è importante, infatti solo avendo i privilegi di
- amministratore si può cambiare il gruppo di un processo ad un'altro di cui
+ amministratore si può cambiare il gruppo di un processo ad un altro di cui
non si fa parte, per cui chiamare prima \func{setuid} farebbe fallire una
successiva chiamata a \func{setgid}. Inoltre si ricordi (si riveda quanto
esposto in sez.~\ref{sec:proc_perms}) che usando queste due funzioni il
interfaccia locale.
A questo punto si può lanciare il client, esso chiamerà \func{socket} e
-\func{connect}; una volta completato il \textit{three way handshake} la
-connessione è stabilita; la \func{connect} ritornerà nel client\footnote{si
- noti che è sempre la \func{connect} del client a ritornare per prima, in
- quanto questo avviene alla ricezione del secondo segmento (l'ACK del server)
- del \textit{three way handshake}, la \func{accept} del server ritorna solo
- dopo un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene
- ricevuto.} e la \func{accept} nel server, ed usando di nuovo \cmd{netstat}
-otterremmo che:
+\func{connect}; una volta completato il \itindex{three~way~handshake}
+\textit{three way handshake} la connessione è stabilita; la \func{connect}
+ritornerà nel client\footnote{si noti che è sempre la \func{connect} del
+ client a ritornare per prima, in quanto questo avviene alla ricezione del
+ secondo segmento (l'ACK del server) del \textit{three way handshake}, la
+ \func{accept} del server ritorna solo dopo un altro mezzo RTT quando il
+ terzo segmento (l'ACK del client) viene ricevuto.} e la \func{accept} nel
+server, ed usando di nuovo \cmd{netstat} otterremmo che:
\begin{verbatim}
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
\includecodesample{listati/SignalRestart.c}
\end{minipage}
\normalsize
- \caption{La funzione \funcd{SignalRestart}, che installa un gestore di
+ \caption{La funzione \func{SignalRestart}, che installa un gestore di
segnali in semantica BSD per il riavvio automatico delle system call
interrotte.}
\label{fig:sig_SignalRestart_code}
dell'entrata nel ciclo principale è stata quella di aver introdotto, subito
dopo la chiamata (\texttt{\small 17--20}) alla funzione \func{listen}, una
eventuale pausa con una condizione (\texttt{\small 21}) sulla variabile
-\var{waiting}, che viene inizializzata, con l'opzione \code{-w Nsec}, al
+\var{waiting}, che viene inizializzata, con l'opzione \texttt{-w Nsec}, al
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 critica, che può essere
+perché nel server l'unica chiamata ad una system call lenta, che può essere
interrotta dall'arrivo di \const{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
con dei server molto occupati. In tal caso, con una struttura del server
simile a quella del nostro esempio, in cui la gestione delle singole
connessioni è demandata a processi figli, può accadere che il \textit{three
- way handshake}\index{\textit{three~way~handshake}} venga completato e la
-relativa connessione abortita subito dopo, prima che il padre, per via del
-carico della macchina, abbia fatto in tempo ad eseguire la chiamata ad
-\func{accept}. Di nuovo si ha una situazione analoga a quella illustrata in
+ way handshake}\itindex{three~way~handshake} venga completato e la relativa
+connessione abortita subito dopo, prima che il padre, per via del carico della
+macchina, abbia fatto in tempo ad eseguire la chiamata ad \func{accept}. Di
+nuovo si ha una situazione analoga a quella illustrata in
fig.~\ref{fig:TCP_early_abort}, in cui la connessione viene stabilita, ma
subito dopo si ha una condizione di errore che la chiude prima che essa sia
stata accettata dal programma.
Le prime tre righe vengono prodotte al momento in cui lanciamo il nostro
client, e corrispondono ai tre pacchetti del
-\index{\textit{three~way~handshake}}\textit{three way handshake}. L'output
-del comando riporta anche i numeri di sequenza iniziali, mentre la lettera
+\itindex{three~way~handshake}\textit{three way handshake}. L'output del
+comando riporta anche i numeri di sequenza iniziali, mentre la lettera
\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti
come a partire dal secondo pacchetto sia sempre attivo il campo \texttt{ack},
seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a
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 \textit{three way handshake}\index{\textit{three~way~handshake}} non
-avremo nulla fin tanto che non scriveremo una prima riga sul client; al
-momento in cui facciamo questo si genera una sequenza di altri quattro
-pacchetti. Il primo, dal client al server, contraddistinto da una lettera
-\texttt{P} che significa che il flag PSH è impostato, contiene la nostra riga
-(che è appunto di 11 caratteri), e ad esso il server risponde immediatamente
-con un pacchetto vuoto di ricevuto. Poi tocca al server riscrivere indietro
-quanto gli è stato inviato, per cui sarà lui a mandare indietro un terzo
-pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal
-client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel
-client che lo stamperà a video.
+del \textit{three way handshake}\itindex{three~way~handshake} non avremo nulla
+fin tanto che non scriveremo una prima riga sul client; al momento in cui
+facciamo questo si genera una sequenza di altri quattro pacchetti. Il primo,
+dal client al server, contraddistinto da una lettera \texttt{P} che significa
+che il flag PSH è impostato, contiene la nostra riga (che è appunto di 11
+caratteri), e ad esso il server risponde immediatamente con un pacchetto vuoto
+di ricevuto. Poi tocca al server riscrivere indietro quanto gli è stato
+inviato, per cui sarà lui a mandare indietro un terzo pacchetto con lo stesso
+contenuto appena ricevuto, e a sua volta riceverà dal client un ACK nel quarto
+pacchetto. Questo causerà la ricezione dell'eco nel client che lo stamperà a
+video.
A questo punto noi procediamo ad interrompere l'esecuzione del server con un
\texttt{C-c} (cioè con l'invio di \const{SIGTERM}): nel momento in cui