client, inoltre anche il server deve inviare il suo SYN al client (e
trasmettere il suo numero di sequenza iniziale) questo viene fatto
ritrasmettendo un singolo segmento in cui sono impostati entrambi i flag SYN
- ACK.
+ e ACK.
\item una volta che il client ha ricevuto l'acknowledge dal server la funzione
\func{connect} ritorna, l'ultimo passo è dare dare il ricevuto del SYN del
\end{figure}
Si è accennato in precedenza ai \textsl{numeri di sequenza} (che sono anche
-riportati in \figref{fig:TCP_TWH}); per gestire una connessione affidabile
+riportati in \figref{fig:TCP_TWH}): per gestire una connessione affidabile
infatti il protocollo TCP prevede nell'header la presenza di un numero a 32
bit (chiamato appunto \textit{sequence number}) che identifica a quale byte
nella sequenza del flusso corrisponde il primo byte della sezione dati
\subsection{La terminazione della connessione}
\label{sec:TCP_conn_term}
-Mentre per creare una connessione occorre un interscambio di tre segmenti, la
-procedura di chiusura ne richiede quattro; ancora una volta si può fare
-riferimento al codice degli esempi \figref{fig:TCP_daytime_client_code} e
-\figref{fig:TCP_daytime_iter_server_code}, in questo caso la successione degli
-eventi è la seguente:
+Mentre per la creazione di una connessione occorre un interscambio di tre
+segmenti, la procedura di chiusura ne richiede normalmente quattro. In questo
+caso la successione degli eventi è la seguente:
\begin{enumerate}
\item Un processo ad uno dei due capi chiama la funzione \func{close}, dando
l'avvio a quella che viene chiamata \textsl{chiusura attiva} (o
\textit{active close}). Questo comporta l'emissione di un segmento FIN, che
- significa che si è finito con l'invio dei dati sulla connessione.
+ serve ad indicare che si è finito con l'invio dei dati sulla connessione.
-\item L'altro capo della connessione riceve il FIN ed esegue la
- \textsl{chiusura passiva} (o \textit{passive close}); al FIN, come ad ogni
- altro pacchetto, viene risposto con un ACK. Inoltre il ricevimento del FIN
+\item L'altro capo della connessione riceve il FIN e dovrà eseguire la
+ \textsl{chiusura passiva} (o \textit{passive close}). Al FIN, come ad ogni
+ altro pacchetto, viene risposto con un ACK, inoltre il ricevimento del FIN
viene segnalato al processo che ha aperto il socket (dopo che ogni altro
eventuale dato rimasto in coda è stato ricevuto) come un end-of-file sulla
- lettura, questo perché il ricevimento di un FIN significa che non si
+ lettura: questo perché il ricevimento di un FIN significa che non si
riceveranno altri dati sulla connessione.
-
-\item Dopo un certo tempo anche il secondo processo chiamerà la funzione
- \func{close} sul proprio socket, causando l'emissione di un altro segmento
- FIN.
+
+\item Una volta rilevata l'end-of-file anche il secondo processo chiamerà la
+ funzione \func{close} sul proprio socket, causando l'emissione di un altro
+ segmento FIN.
\item L'altro capo della connessione riceverà il FIN conclusivo e risponderà
con un ACK.
(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
-minuti.
-
-Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due motivi
-principali:
+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
in entrambe le direzioni.
Se il TCP deve poter chiudere in maniera pulita entrambe le direzioni della
connessione allora deve essere in grado di affrontare la perdita di uno
qualunque dei quattro segmenti che costituiscono la chiusura. Per questo
-motivo lo stato \texttt{TIME\_WAIT} deve essere mantenuto anche dopo l'invio
-dell'ultimo ACK per poter essere in grado di poterne gestire l'eventuale
-ritrasmissione in caso di perdita.
+motivo un socket deve rimanere attivo nello stato \texttt{TIME\_WAIT} anche
+dopo l'invio dell'ultimo ACK, per potere essere in grado di gestirne
+l'eventuale ritrasmissione, in caso esso venga perduto.
Il secondo motivo è più complesso da capire, e necessita di una spiegazione
-degli scenari in cui accade che i pacchetti si possano perdere nella rete o
-restare intrappolati, per poi riemergere in un secondo tempo.
+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.
Il caso più comune in cui questo avviene è quello di anomalie
nell'instradamento; può accadere cioè che un router smetta di funzionare o che
un terzo router che li rispedisce al primo, si creano cioè dei circoli (i
cosiddetti \textit{routing loop}) in cui restano intrappolati i pacchetti.
-Se uno di questi pacchetti intrappolati è un segmento TCP chi l'ha inviato,
+Se uno di questi pacchetti intrappolati è un segmento TCP, chi l'ha inviato,
non ricevendo un ACK in risposta, provvederà alla ritrasmissione e se nel
frattempo sarà stata stabilita una strada alternativa il pacchetto ritrasmesso
giungerà a destinazione.
Ma se dopo un po' di tempo (che non supera il limite dell'MSL, dato che
-altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare il circolo di
+altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare, il circolo di
instradamento viene spezzato i pacchetti intrappolati potranno essere inviati
alla destinazione finale, con la conseguenza di avere dei pacchetti duplicati;
questo è un caso che il TCP deve essere in grado di gestire.
Allora per capire la seconda ragione per l'esistenza dello stato
\texttt{TIME\_WAIT} si consideri il caso seguente: si supponga di avere una
connessione fra l'IP \texttt{195.110.112.236} porta 1550 e l'IP
-\texttt{192.84.145.100} porta 22, che questa venga chiusa e che poco dopo si
+\texttt{192.84.145.100} porta 22 (affronteremo il significato delle porte
+nella prossima sezione), che questa venga chiusa e che poco dopo si
ristabilisca la stessa connessione fra gli stessi IP sulle stesse porte
(quella che viene detta, essendo gli stessi porte e numeri IP, una nuova
\textsl{incarnazione} della connessione precedente); in questo caso ci si
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 \textit{ssh}) effettuati da appositi server che rispondono alle
-connessioni verso tali porte.
+servizio SSH) effettuati da appositi 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
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 corrente si può trovare all'indirizzo
+internet (una versione aggiornata si può trovare all'indirizzo
\texttt{ftp://ftp.isi.edu/in-notes/iana/assignements/port-numbers}); inoltre
in un sistema unix-like un analogo elenco viene mantenuto nel file
\file{/etc/services}, con la corrispondenza fra i vari numeri di porta ed il
\item \textsl{le porte conosciute}. I numeri da 0 a 1023. Queste sono
controllate e assegnate dalla IANA. Se è possibile la stessa porta è
assegnata allo stesso servizio sia su UDP che su TCP (ad esempio la porta 22
- è assegnata a ssh su entrambi i protocolli, anche se viene usata solo dal
+ è assegnata a SSH su entrambi i protocolli, anche se viene usata solo dal
TCP).
\item \textsl{le porte registrate}. I numeri da 1024 a 49151. Queste porte non
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
porte conosciute). La loro caratteristica è che possono essere assegnate a un
-socket solo da un processo con i privilegi di amministratore, per far si che solo
-l'amministratore possa allocare queste porte per far partire i relativi
+socket solo da un processo con i privilegi di amministratore, per far si che
+solo l'amministratore possa allocare queste porte per far partire i relativi
servizi.
-Si tenga conto poi che ci sono alcuni client (in particolare \cmd{rsh} e
-\cmd{rlogin}) che richiedono una connessione su una porta riservata anche
-dal lato client come parte dell'autenticazione. Questo viene fatto tramite la
-funzione \func{rresvport} assegnando al socket una porta libera
-nell'intervallo fra 512 e 1023.
+Si tenga conto poi che ci sono alcuni client, in particolare \cmd{rsh} e
+\cmd{rlogin}, che richiedono una connessione su una porta riservata anche dal
+lato client come parte dell'autenticazione, contando appunto sul fatto che
+solo l'amministratore può usare queste porte. Data l'assoluta inconsistenza in
+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
\label{sec:TCP_port_cliserv}
Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a
-che fare con un'applicazione client/server (come quelle che scriveremo in
+che fare con un'applicazione client/server (come quelle che descriveremo in
\secref{sec:TCP_daytime_application} e \secref{sec:TCP_echo_application})
esamineremo cosa accade con le connessioni nel caso di un server TCP che deve
gestire connessioni multiple.
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
\end{verbatim}
-essendo presenti e attivi un server ssh, un server di posta e un DNS per il
+essendo presenti e attivi un server SSH, un server di posta e un DNS per il
caching locale.
-Questo ci mostra ad esempio che il server ssh ha compiuto un'apertura passiva,
+Questo ci mostra ad esempio che il server SSH ha compiuto un'apertura passiva,
mettendosi in ascolto sulla porta 22 riservata a questo servizio, e che si è
posto in ascolto per connessioni provenienti da uno qualunque degli indirizzi
associati alle interfacce locali. La notazione \texttt{0.0.0.0} usata da
porta 21101 al secondo.
-\section{Le funzioni dei socket TCP}
+\section{Le funzioni di base per la gestione dei socket}
\label{sec:TCP_functions}
-In questa sezione descriveremo in dettaglio le varie funzioni necessarie per
-l'uso dei socket TCP, con l'eccezione della funzione \func{socket} che è già
-stata esaminata in dettaglio nel capitolo precedente in
-\secref{sec:sock_socket}.
+In questa sezione descriveremo in maggior dettaglio le varie funzioni che
+vengono usate per la gestione di base dei socket TCP, non torneremo però sulla
+funzione \func{socket}, che è già stata esaminata accuratamente nel capitolo
+precedente in \secref{sec:sock_socket}.
\subsection{La funzione \func{bind}}
l'indirizzo (locale) del socket e la dimensione della struttura che lo
contiene, secondo quanto già trattato in \secref{sec:sock_sockaddr}.
-Con il TCP la chiamata \func{bind} permette di specificare l'indirizzo, la
-porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
+Con i socket TCP la chiamata \func{bind} permette di specificare l'indirizzo,
+la porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
nota che assegnano all'avvio, se questo non viene fatto è il kernel a
scegliere una porta effimera quando vengono eseguite la funzioni
\func{connect} o \func{listen}, ma se questo è normale per il client non lo è
Normalmente un client non specifica mai l'indirizzo di un socket, ed il kernel
sceglie l'indirizzo di origine quando viene effettuata la connessione, sulla
-base dell'interfaccia usata per trasmettere i pacchetti, (che dipende dalle
+base dell'interfaccia usata per trasmettere i pacchetti, (che dipenderà dalle
regole di instradamento usate per raggiungere il server). Se un server non
specifica il suo indirizzo locale il kernel userà come indirizzo di origine
l'indirizzo di destinazione specificato dal SYN del client.
Stabilisce una connessione fra due socket.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
- errore, in caso di errore \var{errno} assumerà i valori:
+ errore, nel qual caso \var{errno} assumerà i valori:
\begin{errlist}
\item[\errcode{ECONNREFUSED}] non c'è nessuno in ascolto sull'indirizzo
remoto.
Infatti con i socket è comune che funzioni come \func{read} o \func{write}
possano restituire in input o scrivere in output un numero di byte minore di
quello richiesto. Come già accennato in \secref{sec:file_read} questo è un
-comportamento normale per l'I/O su file, ma con i normali file di dati il
-problema si avverte solo quando si incontra la fine del file. In generale non
-è così, e con i socket questo è particolarmente evidente.
+comportamento normale per le funzioni di I/O, ma con i normali file di dati il
+problema si avverte solo in lettura, quando si incontra la fine del file. In
+generale non è così, e con i socket questo è particolarmente evidente.
\begin{figure}[htb]
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
l'altro capo è stato chiuso, e quindi non sarà più possibile leggere niente) e
-pertanto si ritorna senza aver concluso la lettura di tutti i byte richiesti.
+pertanto si ritorna senza aver concluso la lettura di tutti i byte
+richiesti. Entrambe le funzioni restituiscono 0 in caso di successo, ed un
+valore negativo in caso di errore, \texttt{FullRead} restituisce il numero di
+byte non letti in caso di end-of-file prematuro.
\subsection{Il client \textit{daytime}}
\label{sec:TCP_daytime_client}
Il primo esempio di applicazione delle funzioni di base illustrate in
-precedenza è relativo alla creazione di un client elementare per il servizio
-\textit{daytime}, un servizio elementare, definito
+\secref{sec:TCP_functions} è relativo alla creazione di un client elementare
+per il servizio \textit{daytime}, un servizio elementare, definito
nell'\href{http://www.ietf.org/rfc/rfc0867.txt}{RFC~867}, che restituisce
l'ora locale della macchina a cui si effettua la richiesta, e che è assegnato
alla porta 13.
Si noti come il figlio operi solo sul socket connesso, chiudendo
immediatamente (\texttt{\small 32}) il socket \var{list\_fd}; mentre il padre
-continua ad operare solo sul socket in ascolto chiudendo (\texttt{\small 47})
+continua ad operare (\texttt{\small 47}) solo sul socket in ascolto chiudendo
\var{sock\_fd} al ritorno dalla \func{fork}. Per quanto abbiamo detto in
\secref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa
l'innesco della sequenza di chiusura perché il numero di riferimenti al file
\secref{sec:sock_io_behav}, per scrivere i dati sul socket, gestendo
automaticamente l'invio multiplo qualora una singola \func{write} non sia
sufficiente. I dati vengono riletti indietro (\texttt{\small 7}) con una
-\func{FullRead} sul buffer di ricezione e viene inserita (\texttt{\small 8})
-la terminazione della stringa e per poter usare (\texttt{\small 9}) la
-funzione \func{fputs} per scriverli su \file{stdout}.
+\func{read}\footnote{si è fatta l'assunzione implicita che i dati siano
+ contenuti tutti in un solo segmento, così che la chiamata a \texttt{read} li
+ restituisca sempre tutti; avendo scelto una dimensione ridotta per il buffer
+ questo sarà sempre vero, vedremo più avanti come superare il problema di
+ rileggere indietro tutti e soli i dati disponibili, senza bloccarsi.} sul
+buffer di ricezione e viene inserita (\texttt{\small 8}) la terminazione della
+stringa e per poter usare (\texttt{\small 9}) la funzione \func{fputs} per
+scriverli su \file{stdout}.
\begin{figure}[!htb]
\footnotesize \centering
\textit{wrapper} la funzione \code{PrintErr}, il cui codice è riportato in
\figref{fig:TCP_PrintErr}.
-In essa ci si limita a controllare se è stato impostato (valore attivo per
-default) l'uso come demone, nel qual caso (\texttt{\small 3}) si usa
-\func{syslog} per stampare il messaggio di errore fornito come argomento sui
-log di sistema. Se invece si è in modalità interattiva (attivabile con
-l'opzione \texttt{-i}) si usa semplicemente la funzione \func{perror} per
-stampare sullo standard error.
-
+In essa ci si limita a controllare (\texttt{\small 2}) se è stato impostato
+(valore attivo per default) l'uso come demone, nel qual caso (\texttt{\small
+ 3}) si usa \func{syslog} (vedi \secref{sec:sess_daemon}) per stampare il
+messaggio di errore fornito come argomento sui log di sistema. Se invece si è
+in modalità interattiva (attivabile con l'opzione \texttt{-i}) si usa
+(\texttt{\small 5}) semplicemente la funzione \func{perror} per stampare sullo
+standard error.
\begin{figure}[!htb]
\footnotesize \centering
La gestione del servizio \textit{echo} viene effettuata interamente nella
funzione \code{ServEcho}, il cui codice è mostrato in
-\figref{fig:TCP_ServEcho}, la comunicazione viene gestita all'interno del
-ciclo (\texttt{\small 6--8}). I dati inviati dal client vengono letti dal
-socket con una semplice \func{read} (che ritorna solo in presenza di dati in
-arrivo), la riscrittura viene invece gestita dalla funzione \func{FullWrite}
-(descritta in \figref{fig:sock_FullWrite_code}) che si incarica di tenere
-conto automaticamente della possibilità che non tutti i dati di cui è
-richiesta la scrittura vengano trasmessi con una singola \func{write}.
+\figref{fig:TCP_ServEcho}, e la comunicazione viene gestita all'interno di un
+ciclo (\texttt{\small 6--13}). I dati inviati dal client vengono letti
+(\texttt{\small 6}) dal socket con una semplice \func{read}, di cui non si
+controlla lo stato di uscita, assumendo che ritorni solo in presenza di dati
+in arrivo. La riscrittura (\texttt{\small 7}) viene invece gestita dalla
+funzione \func{FullWrite} (descritta in \figref{fig:sock_FullWrite_code}) che
+si incarica di tenere conto automaticamente della possibilità che non tutti i
+dati di cui è richiesta la scrittura vengano trasmessi con una singola
+\func{write}.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15.6cm}
- \includecodesample{listati/ServEcho.c}
+ \includecodesample{listati/ServEcho_first.c}
\end{minipage}
\normalsize
\caption{Codice della prima versione della funzione \code{ServEcho} per la
\label{fig:TCP_ServEcho}
\end{figure}
-Nella funzione si è anche inserita la possibilità (\texttt{\small 7--14}) di
-inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d}
-che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui
-la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 11}) o
-direttamente sullo standard output (\texttt{\small 13}).
-
-Quando il client chiude la connessione il ricevimento del FIN fa ritornare la
-\func{read} con un numero di byte letti pari a zero, il che causa l'uscita dal
-ciclo e il ritorno della funzione, che a sua volta causa la terminazione del
+In caso di errore di scrittura (si ricordi che \func{FullWrite} restituisce un
+vamore nullo in caso di successo) si provvede (\texttt{\small 8--10}) a
+stampare il relativo messaggio con \func{PrintErr}. Quando il client chiude
+la connessione il ricevimento del FIN fa ritornare la \func{read} con un
+numero di byte letti pari a zero, il che causa l'uscita dal ciclo e il ritorno
+(\texttt{\small 12}) della funzione, che a sua volta causa la terminazione del
processo figlio.
\label{sec:TCP_echo_startup}
Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
-di considerare in dettaglio tutte le problematiche che si possono incontrare
+di considerare in dettaglio le varie problematiche che si possono incontrare
nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue
modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
che avviene nelle varie situazioni limite, da una parte potremo approfondire
\begin{enumerate}
\item inviando un carattere di EOF da terminale la \func{fgets} ritorna
- restituendo un puntatore nullo che causa l'uscita dal ciclo di
- \code{while}, così la \code{ClientEcho} ritorna.
+ restituendo un puntatore nullo che causa l'uscita dal ciclo di \code{while},
+ così la funzione \code{ClientEcho} ritorna.
\item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e
come parte del processo terminazione tutti i file descriptor vengono chiusi
(si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
+Nella funzione si è anche inserita (\texttt{\small 16--24}) la possibilità di
+inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d}
+che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui
+la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 20}) o
+direttamente sullo standard output (\texttt{\small 22}).
+
+
+
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"