elementare di dati trasmessa dal protocollo TCP al livello successivo; tutti
i segmenti hanno un'intestazione che contiene le informazioni che servono
allo \textit{stack TCP} (così viene di solito chiamata la parte del kernel
- che implementa il protocollo) per realizzare la comunicazione, fra questi
- dati ci sono una serie di flag usati per gestire la connessione, come SYN,
- ACK, URG, FIN, alcuni di essi, come SYN (che sta per \textit{syncronize})
+ che realizza il protocollo) per effettuare la comunicazione, fra questi dati
+ ci sono una serie di flag usati per gestire la connessione, come SYN, ACK,
+ URG, FIN, alcuni di essi, come SYN (che sta per \textit{syncronize})
corrispondono a funzioni particolari del protocollo e danno il nome al
segmento, (per maggiori dettagli vedere sez.~\ref{sec:tcp_protocol}).} di
dati che vengono scambiati) che porta alla creazione di una connessione è la
\textsl{apertura attiva}, dall'inglese \textit{active open}. La chiamata di
\func{connect} blocca il processo e causa l'invio da parte del client di un
segmento SYN, in sostanza viene inviato al server un pacchetto IP che
- contiene solo le instestazioni di IP e TCP (con il numero di sequenza
+ contiene solo le intestazioni di IP e TCP (con il numero di sequenza
iniziale e il flag SYN) e le opzioni di TCP.
\item Il server deve dare ricevuto (l'\textit{acknowledge}) del SYN del
possibile leggere e scrivere questo valore attraverso l'opzione del socket
\const{TCP\_MAXSEG} (vedi sez.~\ref{sec:sock_tcp_udp_options}).
-\item \textit{window scale option}, il protocollo TCP implementa il controllo
- di flusso attraverso una \textit{advertised window} (la ``\textsl{finestra
- annunciata}'', vedi sez.~\ref{sec:tcp_protocol}) 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.
+\item \textit{window scale option}, il protocollo TCP realizza il controllo di
+ flusso attraverso una \textit{advertised window} (la ``\textsl{finestra
+ annunciata}'', vedi sez.~\ref{sec:tcp_protocol}) 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 realizzazione dello \textit{stack TCP} che usano
+ l'aritmetica con segno.} 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 un'altra opzione che indica un fattore di scala da
applicare al valore della finestra annunciata per la connessione corrente
(espresso come numero di bit cui spostare a sinistra il valore della
finestra annunciata inserito nel pacchetto). 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
+ garantire la compatibilità con delle vecchie realizzazione 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.
+ SYN di risposta dell'apertura della connessione.
Con Linux è possibile indicare al kernel di far negoziare il fattore di
scala in fase di creazione di una connessione tramite la \textit{sysctl}
\end{itemize}
La \textit{MSS option} è generalmente supportata da quasi tutte le
-implementazioni del protocollo, le ultime due opzioni (trattate
+realizzazioni del protocollo, le ultime due opzioni (trattate
nell'\href{http://www.ietf.org/rfc/rfc1323.txt}{RFC~1323}) sono meno comuni;
vengono anche dette \textit{long fat pipe options} dato che questo è il nome
che viene dato alle connessioni caratterizzate da alta velocità o da ritardi
\texttt{TIME\_WAIT}, sul cui significato torneremo fra poco.
È da notare come per effettuare uno scambio di due pacchetti (uno di richiesta
-e uno di risposta) il TCP necessiti di ulteriori otto segmenti, se invece si
+e uno di risposta) TCP necessiti di ulteriori otto segmenti, se invece si
fosse usato UDP sarebbero stati sufficienti due soli pacchetti. Questo è il
-costo che occorre pagare per avere l'affidabilità garantita dal TCP, se si
+costo che occorre pagare per avere l'affidabilità garantita da TCP, se si
fosse usato UDP si sarebbe dovuto trasferire la gestione di tutta una serie di
dettagli (come la verifica della ricezione dei pacchetti) dal livello del
trasporto all'interno dell'applicazione.
specifico le sue caratteristiche di velocità e compattezza nello scambio dei
dati rispondono meglio alle esigenze che devono essere affrontate.
+
\subsection{Lo stato \texttt{TIME\_WAIT}}
\label{sec:TCP_time_wait}
router; quando si annulla il pacchetto viene scartato. Siccome il numero è ad
8 bit il numero massimo di ``\textsl{salti}'' è di 255, pertanto anche se il
TTL (da \textit{time to live}) non è propriamente un limite sul tempo, sulla
-sua base si stimare che un pacchetto IP non possa restare nella rete per più
-un certo numero di secondi che costituisce la \textit{Maximum Segment Lifetime}.
-
-Ogni implementazione del TCP deve scegliere un valore per la MSL
-(l'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} raccomanda 2 minuti,
-Linux usa 30 secondi), questo comporta una durata dello stato
-\texttt{TIME\_WAIT} che a seconda delle implementazioni può variare fra 1 a 4
+sua base si può stimare che un pacchetto IP non possa restare nella rete per
+più un certo numero di secondi, che costituisce la \textit{Maximum Segment
+ Lifetime}.
+
+Ogni realizzazione del TCP deve scegliere un valore per la MSL;
+l'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} raccomanda 2 minuti,
+mentre Linux usa 30 secondi, questo comporta una durata dello stato
+\texttt{TIME\_WAIT} che a seconda delle realizzazioni può variare fra 1 a 4
minuti. Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due
motivi principali:
-\begin{enumerate}
-\item implementare in maniera affidabile la terminazione della connessione
+\begin{enumerate*}
+\item effettuare in maniera affidabile la terminazione della connessione
in entrambe le direzioni.
\item consentire l'eliminazione dei segmenti duplicati dalla rete.
-\end{enumerate}
+\end{enumerate*}
Il punto è che entrambe le ragioni sono importanti, anche se spesso si fa
riferimento solo alla prima; ma è solo se si tiene conto della seconda che si
Il secondo motivo è più complesso da capire, e necessita di una spiegazione
degli scenari in cui può accadere che i pacchetti TCP si possano perdere nella
-rete o restare intrappolati, per poi riemergere in un secondo tempo.
+rete o restare intrappolati, per poi riemergere in un secondo tempo.
Il caso più comune in cui questo avviene è quello di anomalie
nell'instradamento; può accadere cioè che un router smetta di funzionare o che
sez.~\ref{sec:sock_sa_ipv4} e sez.~\ref{sec:sock_sa_ipv6} pure delle strutture
degli indirizzi del socket.
-Quando un client contatta un server deve poter identificare con quale dei vari
-possibili server attivi intende parlare. Sia TCP che UDP definiscono un gruppo
-di \textsl{porte conosciute} (le cosiddette \textit{well-known port}) che
-identificano una serie di servizi noti (ad esempio la porta 22 identifica il
-servizio SSH) effettuati da appositi server che rispondono alle connessioni
-verso tali porte.
+Quando un client contatta una macchina server deve poter identificare con
+quale dei vari possibili programmi server attivi intende parlare. Sia TCP che
+UDP definiscono un gruppo di \textsl{porte conosciute} (le cosiddette
+\textit{well-known port}) che identificano una serie di servizi noti (ad
+esempio la porta 22 identifica il servizio SSH) effettuati da appositi
+programmi server che rispondono alle connessioni verso tali porte.
-D'altra parte un client non ha necessità di usare un numero di porta
-specifico, per cui in genere vengono usate le cosiddette \textsl{porte
+D'altra parte un client non ha necessità di usare dalla sua parte un numero di
+porta specifico, per cui in genere vengono usate le cosiddette \textsl{porte
effimere} (o \textit{ephemeral ports}) cioè porte a cui non è assegnato
nessun servizio noto e che vengono assegnate automaticamente dal kernel alla
creazione della connessione. Queste sono dette effimere in quanto vengono
dall'\href{http://www.ietf.org/rfc/rfc1700.txt}{RFC~1700} che contiene
l'elenco delle porte assegnate dalla IANA (la \textit{Internet Assigned Number
Authority}) ma l'elenco viene costantemente aggiornato e pubblicato su
-internet (una versione aggiornata si può trovare all'indirizzo
+Internet (una versione aggiornata si può trovare all'indirizzo
\url{http://www.iana.org/assignments/port-numbers}); inoltre in un sistema
unix-like un analogo elenco viene mantenuto nel file \conffile{/etc/services},
con la corrispondenza fra i vari numeri di porta ed il nome simbolico del
\item \textsl{le porte registrate}. I numeri da 1024 a 49151. Queste porte non
sono controllate dalla IANA, che però registra ed elenca chi usa queste
porte come servizio agli utenti. Come per le precedenti si assegna una porta
- ad un servizio sia per TCP che UDP anche se poi il servizio è implementato
- solo su TCP. Ad esempio X Window usa le porte TCP e UDP dal 6000 al 6063
- anche se il protocollo è implementato solo tramite TCP.
+ ad un servizio sia per TCP che UDP anche se poi il servizio è effettuato
+ solo su TCP. Ad esempio \textit{X Window} usa le porte TCP e UDP dal 6000 al
+ 6063 anche se il protocollo viene usato solo con TCP.
\item \textsl{le porte private} o \textsl{dinamiche}. I numeri da 49152 a
65535. La IANA non dice nulla riguardo a queste porte che pertanto
\label{fig:TCP_port_alloc}
\end{figure}
-I sistemi Unix hanno inoltre il concetto di \textsl{porte riservate} (che
+I sistemi Unix hanno inoltre il concetto di \textsl{porte riservate}, che
corrispondono alle porte con numero minore di 1024 e coincidono quindi con le
-\textsl{porte note}). La loro caratteristica è che possono essere assegnate a
+\textsl{porte note}. La loro caratteristica è che possono essere assegnate a
un socket solo da un processo con i privilegi di amministratore, per far sì
che solo l'amministratore possa allocare queste porte per far partire i
relativi servizi.
-Le \textsl{glibc} definiscono in \headfile{netinet/in.h}
+Le \textsl{glibc} definiscono in \headfile{netinet/in.h} le costanti
\constd{IPPORT\_RESERVED} e \constd{IPPORT\_USERRESERVED}, in cui la prima
(che vale 1024) indica il limite superiore delle porte riservate, e la seconda
(che vale 5000) il limite inferiore delle porte a disposizione degli utenti.
termini di sicurezza di un tale metodo, al giorno d'oggi esso è in completo
disuso.
-Data una connessione TCP si suole chiamare \textit{socket pair}\footnote{da
- non confondere con la coppia di socket della omonima funzione
- \func{socketpair} che fanno riferimento ad una coppia di socket sulla stessa
- macchina, non ai capi di una connessione TCP.} la combinazione dei quattro
-numeri che definiscono i due capi della connessione e cioè l'indirizzo IP
-locale e la porta TCP locale, e l'indirizzo IP remoto e la porta TCP remota.
-Questa combinazione, che scriveremo usando una notazione del tipo
+Data una connessione TCP si suole chiamare \textit{socket pair} (da non
+confondere con la coppia di socket della omonima funzione \func{socketpair} di
+sez.~\ref{sec:ipc_socketpair} che fanno riferimento ad una coppia di socket
+sulla stessa macchina, non ai capi di una connessione TCP) la combinazione dei
+quattro numeri che definiscono i due capi della connessione e cioè l'indirizzo
+IP locale e la porta TCP locale, e l'indirizzo IP remoto e la porta TCP
+remota. Questa combinazione, che scriveremo usando una notazione del tipo
(\texttt{195.110.112.152:22}, \texttt{192.84.146.100:20100}), identifica
-univocamente una connessione su internet. Questo concetto viene di solito
+univocamente una connessione su Internet. Questo concetto viene di solito
esteso anche a UDP, benché in questo caso non abbia senso parlare di
connessione. L'utilizzo del programma \cmd{netstat} permette di visualizzare
queste informazioni nei campi \textit{Local Address} e \textit{Foreing
code. Stevens in \cite{UNP1} riporta che BSD ha sempre applicato un fattore di
1.5 a detto valore, e fornisce una tabella con i risultati ottenuti con vari
kernel, compreso Linux 2.0, che mostrano le differenze fra diverse
-implementazioni.
+realizzazioni.
In Linux il significato di questo valore è cambiato a partire dal kernel 2.2
per prevenire l'attacco chiamato \itindex{SYN~flood} \textit{SYN
connessione viene eseguito con la funzione \func{close}.
È da chiarire che Linux presenta un comportamento diverso nella gestione degli
-errori rispetto ad altre implementazioni dei socket BSD, infatti la funzione
+errori rispetto ad altre realizzazioni dei socket BSD, infatti la funzione
\func{accept} passa gli errori di rete pendenti sul nuovo socket come codici
di errore per \func{accept}, per cui l'applicazione deve tenerne conto ed
eventualmente ripetere la chiamata alla funzione come per l'errore di
Infine è da chiarire (si legga la pagina di manuale) che, come per
\func{accept}, il terzo argomento, che è specificato dallo standard POSIX.1g
come di tipo \code{socklen\_t *} in realtà deve sempre corrispondere ad un
-\ctyp{int *} come prima dello standard perché tutte le implementazioni dei
+\ctyp{int *} come prima dello standard perché tutte le realizzazioni dei
socket BSD fanno questa assunzione.
Avendo introdotto le funzioni di base per la gestione dei socket, potremo
vedere in questa sezione un primo esempio di applicazione elementare che
-implementa il servizio \textit{daytime} su TCP, secondo quanto specificato
+realizza il servizio \textit{daytime} su TCP, secondo quanto specificato
dall'\href{http://www.ietf.org/rfc/rfc867.txt}{RFC~867}. Prima di passare
agli esempi del client e del server, inizieremo riesaminando con maggiori
dettagli una peculiarità delle funzioni di I/O, già accennata in
-sez.~\ref{sec:file_read} e sez.~\ref{sec:file_write}, che nel caso dei socket è
-particolarmente rilevante. Passeremo poi ad illustrare gli esempi
-dell'implementazione, sia dal lato client, che dal lato server, che si è
-realizzato sia in forma iterativa che concorrente.
+sez.~\ref{sec:file_read} e sez.~\ref{sec:file_write}, che nel caso dei socket
+è particolarmente rilevante. Passeremo poi ad illustrare gli esempi della
+realizzazione, sia dal lato client, che dal lato server, che si è effettuata
+sia in forma iterativa che concorrente.
\subsection{Il comportamento delle funzioni di I/O}
un po' più complessa, che usi i socket TCP per una comunicazione in entrambe
le direzioni.
-Ci limiteremo a fornire una implementazione elementare, che usi solo le
-funzioni di base viste finora, ma prenderemo in esame, oltre al comportamento
-in condizioni normali, anche tutti i possibili scenari particolari (errori,
+Ci limiteremo a fornire una realizzazione elementare, che usi solo le funzioni
+di base viste finora, ma prenderemo in esame, oltre al comportamento in
+condizioni normali, anche tutti i possibili scenari particolari (errori,
sconnessione della rete, crash del client o del server durante la connessione)
che possono avere luogo durante l'impiego di un'applicazione di rete, partendo
da una versione primitiva che dovrà essere rimaneggiata di volta in volta per
poter tenere conto di tutte le evenienze che si possono manifestare nella vita
-reale di un'applicazione di rete, fino ad arrivare ad un'implementazione
+reale di un'applicazione di rete, fino ad arrivare ad una realizzazione
completa.
certo numero di volte, con tempi di attesa crescente fra un tentativo ed il
successivo, per tentare di ristabilire la connessione.
-Il risultato finale qui dipende dall'implementazione dello stack TCP, e nel
-caso di Linux anche dall'impostazione di alcuni dei parametri di sistema che
-si trovano in \file{/proc/sys/net/ipv4}, che ne controllano il comportamento:
-in questo caso in particolare da \sysctlrelfile{net/ipv4}{tcp\_retries2} (vedi
+Il risultato finale qui dipende dalla realizzazione dello \textit{stack TCP},
+e nel caso di Linux anche dall'impostazione di alcuni dei parametri di sistema
+che si trovano in \file{/proc/sys/net/ipv4}, che ne controllano il
+comportamento: in questo caso in particolare da
+\sysctlrelfile{net/ipv4}{tcp\_retries2} (vedi
sez.~\ref{sec:sock_ipv4_sysctl}). Questo parametro infatti specifica il numero
di volte che deve essere ritentata la ritrasmissione di un pacchetto nel mezzo
di una connessione prima di riportare un errore di timeout. Il valore
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}.}
+connessione.\footnote{ne faremo comunque una realizzazione diversa rispetto a
+ quella presentata da Stevens in \cite{UNP1}.}
La struttura del nuovo server è illustrata in
fig.~\ref{fig:TCP_echo_multiplex}, in questo caso avremo un solo processo che
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 fig.~\ref{fig:TCP_echo_multiplex}, il
-programma usa una tabella dei socket connessi mantenuta nel vettore
-\var{fd\_open} dimensionato al valore di \const{FD\_SETSIZE}, ed una variabile
-\var{max\_fd} per registrare il valore più alto dei file descriptor aperti.
+connessioni o di dati in arrivo, e processarli immediatamente. Per realizzare
+lo schema mostrato in fig.~\ref{fig:TCP_echo_multiplex}, il programma usa una
+tabella dei socket connessi mantenuta nel vettore \var{fd\_open} dimensionato
+al valore di \const{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
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.
+ considerata sia traffico normale che prioritario, nel caso di Linux la
+ realizzazione dello \textit{stack TCP} 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 fig.~\ref{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.
+Come esempio dell'uso di \func{poll} proviamo allora a riscrivere il server
+\textit{echo} secondo lo schema di fig.~\ref{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]
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
+