Scritta una nuova macro per i prototipi delle funzioni. Adesso ci sara` da
[gapil.git] / elemtcp.tex
index 3f256c875ef8838d0e1ecf9957e3f72b8c5fd71c..94612fa7759e2fd4415015a93c33a0dca7adfaf2 100644 (file)
@@ -230,7 +230,6 @@ bench
 principale dei quali è l'HTTP, per i quali è il server ad effettuare la
 chiusura attiva.
 
-
 \subsection{Un esempio di connessione}
 \label{sec:TCPel_conn_dia}
 
@@ -507,9 +506,12 @@ campi \textit{Local Address} e \textit{Foreing Address}.
 \subsection{Le porte ed il modello client/server}
 \label{sec:TCPel_port_cliserv}
 
-Per capire meglio l'uso delle porte e come vengono utilizzate nella
-programmazione di rete consideriamo cosa accade con una serie di esempi, se
-esguiamo un \texttt{netstat} su una macchina di prova (che supponiamo avere
+Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a
+che fare con un'applicazione client/server (come quella che scriveremo in
+\ref{sec:TCPel_echo_example}) esaminaremo cosa accade con le connessioni nel
+caso di un server TCP che deve gestire connessioni multiple.
+
+Se esguiamo un \texttt{netstat} su una macchina di prova (che supponiamo avere
 indirizzo 195.110.112.152) potremo avere un risultato del tipo:
 \begin{verbatim}
 Active Internet connections (servers and established)
@@ -518,8 +520,8 @@ tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
 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 un server ssh, un server di posta e un DNS per il caching
-locale. 
+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
 mettendosi in ascolto sulla porta 22 riservata a questo servizio e che si è
@@ -565,12 +567,12 @@ tcp        0      0 195.110.112.152:22      192.84.146.100:21100    ESTABLISHED
 
 Come si può notare il server è ancora in ascolto sulla porta 22, però adesso
 c'è un nuovo socket (con lo stato \texttt{ESTABLISHED}) che anch'esso utilizza
-la porta 22, ma ha specificato l'indirizzo locale, e che corrisponde al socket
-con cui il processo figlio gestisce la connessione mentre il padre resta in
-ascolto.
+la porta 22, ed ha specificato l'indirizzo locale, questo è il socket con cui
+il processo figlio gestisce la connessione mentre il padre resta in ascolto
+sul socket originale.
 
-Se a questo lanciamo una seconda volta il client ssh per una seconda
-conessione quello che otterremo sarà qualcosa del genere:
+Se a questo punto lanciamo un'altra volta il client ssh per una seconda
+conessione quello che otterremo usando netstat sarà qualcosa del genere:
 \begin{verbatim}
 Active Internet connections (servers and established)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State      
@@ -580,17 +582,17 @@ tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN
 tcp        0      0 195.110.112.152:22      192.84.146.100:21100    ESTABLISHED
 tcp        0      0 195.110.112.152:22      192.84.146.100:21101    ESTABLISHED
 \end{verbatim}
-cioè al client sarà stata assegnata un'altra porta effimera e con questa sarà
-aperta la connessione, ed un nuovo processo figlio sarà creato per gestirla.
-
+cioè il client effettuerà la connessione usando un'altra porta effimera, con
+questa sarà aperta la connessione, ed il server creerà un'altro processo
+figlio sarà creato per gestirla.
 
-Tutto ciò mostra come TCP, per poter gestire le due connessioni, 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 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.
+Tutto ciò mostra come 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 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 dei socket TCP}
@@ -621,6 +623,93 @@ risponder
 Useremo questo schema per l'esempio di implementazione del servizio
 \texttt{echo} che illustreremo in \ref{sec:TCPel_echo_example}. 
 
+
+\subsection{La funzione \texttt{bind}}
+\label{sec:TCPel_func_bind}
+
+
+La funzione \texttt{bind} assegna un indirizzo locale ad un socket, è usata
+cioè per specificare la prima parte dalla socket pair. Viene usata sul lato
+server per specificare la porta (e gli eventuali indirizzi locali) su cui poi
+ci si porrà in ascolto.
+
+Il prototipo della funzione, definito in \texttt{sys/socket.h}, è il seguente:
+
+\begin{itemize}
+\item \texttt{int bind(int sockfd, const struct sockaddr *serv\_addr,
+    socklen\_t addrlen) }
+  
+  Il primo argomento è un file descriptor ottenuto da una precedente chiamata
+  a \texttt{socket}, mentre il secondo e terzo argomento sono rispettivamente
+  l'indirizzo (locale) del socket e la dimensione della struttura che lo
+  contiene, secondo quanto già trattato in \ref{sec:sock_sockaddr}.
+
+  La funzione restituisce zero in caso di successo e -1 per un errore, in caso
+  di errore. La variabile \texttt{errno} viene settata secondo i seguenti
+  codici di errore:
+  \begin{itemize}
+  \item \texttt{EBADF} Il file descriptor non è valido.
+  \item \texttt{EINVAL} Il socket ha già un indirizzo assegnato.
+  \item \texttt{ENOTSOCK} Il file descriptor non è associato ad un socket.
+  \item \texttt{EACCESS} Si è cercato di usare un indirizzo riservato senza
+    essere root. 
+  \end{itemize}
+
+\end{itemize}
+
+Con il TCP la chiamata \texttt{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
+\texttt{connect} o \texttt{listen}, ma se questo è normale per il client non
+lo è per il server\footnote{un'eccezione a tutto ciò i server che usano RPC.
+  In questo caso viene fatta assegnare dal kernel una porta effimera che poi
+  viene registrata presso il \textit{portmapper}; quest'ultimo è un altro
+  demone che deve essere contattato dai client per ottenere la porta effimera
+  su cui si trova il server} che in genere viene identificato dalla porta su
+cui risponde.
+
+Con \texttt{bind} si può assegnare un IP specifico ad un socket, purché questo
+appartenga ad una interfaccia della macchina.  Per un client TCP questo
+diventerà l'indirizzo sorgente usato per i tutti i pacchetti inviati sul
+socket, mentre per un server TCP questo restringerà l'accesso al socket solo
+alle connessioni che arrivano verso tale indirizzo.
+
+Normalmente un client non specifica mai un indirizzo ad un suo socket, ed il
+kernel sceglie l'indirizzo di orgine quando viene effettuata la connessione
+sulla base dell'interfaccia usata per trasmettere i pacchetti, (che dipende
+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. 
+
+Per specificare un indirizzo generico con IPv4 si usa il valore
+\texttt{INADDR\_ANY}, il cui valore, come visto anche negli esempi precedenti
+è pari a zero, nell'esempio \ref{fig:net_serv_sample} si è usata
+un'assegnazione immediata del tipo:
+\begin{verbatim}
+   serv_add.sin_addr.s_addr = htonl(INADDR_ANY);   /* connect from anywhere */
+\end{verbatim}
+
+Si noti che si è usato \texttt{htonl} per assegnare il valore
+\texttt{INADDR\_ANY}; benché essendo questo pari a zero il riordinamento sia
+inutile; ma dato che tutte le constanti \texttt{INADDR\_} sono definite
+secondo l'ordinamento della macchina è buona norma usare sempre la funzione
+\texttt{htonl}.
+
+L'esempio precedete funziona con IPv4 dato che l'indirizzo è rappresentabile
+anche con un intero a 32 bit; non si può usare lo stesso metodo con IPv6,
+in cui l'indirizzo è specificato come struttura, perché il linguaggio C non
+consente l'uso di una struttura costante come operando a destra in una
+assegnazione.  Per questo nell'header \texttt{netinet/in.h} è definita una
+variabile \texttt{in6addr\_any} (dichiarata come \texttt{extern}, ed
+inizializzata dal sistema al valore \texttt{IN6ADRR\_ANY\_INIT}) che permette
+di effettuare una assegnazione del tipo:
+\begin{verbatim}
+   serv_add.sin6_addr = in6addr_any;   /* connect from anywhere */
+\end{verbatim}
+
+
 \subsection{La funzione \texttt{connect}}
 \label{sec:TCPel_func_connect}
 
@@ -629,8 +718,8 @@ connessione con un server TCP, il prototipo della funzione, definito in
 \texttt{sys/socket.h}, è il seguente:
 
 \begin{itemize}
-\item \texttt{int connect(int sockfd, const struct sockaddr *serv_addr,
-    socklen_t addrlen) }
+\item \texttt{int connect(int sockfd, const struct sockaddr *serv\_addr,
+    socklen\_t addrlen) }
   
   Il primo argomento è un file descriptor ottenuto da una precedente chiamata
   a \texttt{socket}, mentre il secondo e terzo argomento sono rispettivamente
@@ -639,18 +728,17 @@ connessione con un server TCP, il prototipo della funzione, definito in
 
   La funzione restituisce zero in caso di successo e -1 per un errore, in caso
   di errore. La variabile \texttt{errno} viene settata secondo i seguenti
-  codici di errore
-
+  codici di errore:
   \begin{itemize}
   \item \texttt{EBADF} Il file descriptor non è valido.
   \item \texttt{EFAULT} L'indirizzo della struttura di indirizzi è al di fuori
     dello spazio di indirizzi dell'utente.
-  \item \texttt{ENOTSOCK} Il file descriptor non è associato ad un socket
+  \item \texttt{ENOTSOCK} Il file descriptor non è associato ad un socket.
   \item \texttt{EISCONN} Il socket è già connesso.
   \item \texttt{ECONNREFUSED} Non c'è nessuno in ascolto sull'indirizzo remoto.
   \item \texttt{ETIMEDOUT} Si è avuto timeout durante il tentativo di
     connessione.
-  \item \texttt{ENETUNREACH} La rete non è rggiungibile/
+  \item \texttt{ENETUNREACH} La rete non è raggiungibile.
   \item \texttt{EADDRINUSE} L'indirizzo locale è in uso.
   \item \texttt{EINPROGRESS} Il socket è non bloccante e la connessione non
     può essere conclusa immediatamente.
@@ -659,7 +747,9 @@ connessione con un server TCP, il prototipo della funzione, definito in
   \item \texttt{EAGAIN} Non ci sono più porte locali libere. 
   \item \texttt{EAFNOSUPPORT} L'indirizzo non ha una famiglia di indirizzi
     corretta nel relativo campo.
-  \item \texttt{EACCESS, EPERM} 
+  \item \texttt{EACCESS, EPERM} Si è tentato di eseguire una connessione ad un
+    indirizzo broacast senza che il socket fosse stato abilitato per il
+    broadcast.
   \end{itemize}
 \end{itemize}
 
@@ -670,25 +760,26 @@ nell'esempio \ref{sec:net_cli_sample} usando le funzioni illustrate in
 
 Nel caso di socket TCP la funzione \texttt{connect} avvia il three way
 handshake, e ritorna solo quando la connessione è stabilita o si è verificato
-un errore. Le possibili cause di errore sono molteplici (e brevemente
-riassunte sopra), in particolare le principali sono:
+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 o problemi nella chiamata della funzione sono le seguenti: 
 
 \begin{enumerate}
-\item Se il client non riceve risposta al SYN l'errore restituito è
+\item Il client non riceve risposta al SYN: l'errore restituito è
   \texttt{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla chiamata
   di \texttt{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
   \texttt{sysctl} che attraverso il filesystem \texttt{/proc} scrivendo il
-  valore voluto in \texttt{/proc/sys/net/ipv4/tcp_syn_retries}. Il valore di
+  valore voluto in \texttt{/proc/sys/net/ipv4/tcp\_syn\_retries}. Il valore di
   default per la ripetizione dell'invio è di 5 volte, che comporta un timeout
   dopo circa 180 secondi.
 %
 % Le informazioni su tutte le opzioni settabili via /proc stanno in
 % linux/Documentation/networking/ip-sysctl.txt
 %
-\item Se il client riceve come risposta al SYN un RST significa che non c'è
+\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 probablmente che o si è sbagliato il numero della porta o che
   non è stato avviato il server), questo è un errore fatale e la funzione
@@ -700,28 +791,53 @@ riassunte sopra), in particolare le principali sono:
   quando arriva un SYN per una porta che non ha nessun server in ascolto,
   quando il TCP abortisce una connessione in corso, quandi TCP riceve un
   segmento per una connessione che non esiste.
-
-\item Il SYN del client provoca l'emissione di un messaggio ICMP di
-  destinazione non raggiungibile. 
   
+\item Il SYN del client provoca l'emissione di un messaggio ICMP di
+  destinazione non raggiungibile. In questo caso dato che il messaggio può
+  essere dovuto ad una condizione transitoria si ripete l'emmissione dei SYN
+  come nel caso precedente, fino al timeout, e solo allora si restituisce il
+  codice di errore dovuto al messaggio ICMP, che da luogo ad un
+  \texttt{ENETUNREACH}.
+   
 \end{enumerate}
 
-\subsection{La funzione \texttt{bind}}
-\label{sec:TCPel_func_bind}
+Se si fa riferimento al diagramma degli stati del TCP riportato in
+\ref{fig:appB:tcp_state_diag} la funzione \texttt{connect} porta un socket
+dallo stato \texttt{CLOSED} (lo stato iniziale in cui si trova un socket
+appena creato) prima allo stato \texttt{SYN\_SENT} e poi, al ricevimento del
+ACK, nello stato \texttt{ESTABLISHED}. Se invece la connessione fallisce il
+socket non è più utilizzabile e deve essere chiuso.
 
+Si noti infine che con la funzione \texttt{connect} si è specificato solo
+indirizzo e porta del server, quindi solo una metà della socket pair; essendo
+questa funzione usata nei client l'altra metà contentente indirizzo e porta
+locale viene lasciata all'assegnazione automatica del kernel, e non è
+necessario effettuare una \texttt{bind}.
 
 
 \subsection{La funzione \texttt{listen}}
 \label{sec:TCPel_func_listen}
 
-\subsection{La funzione \texttt{accept}}
-\label{sec:TCPel_func_accept}
+La funzione \texttt{listen} è usata per usare un socket in modalità passiva,
+cioè, come dice il nome, per metterlo in ascolto di eventuali connessioni; in
+sostanza l'effetto della funzione è di portare il socket dallo stato
+\texttt{CLOSED} a quello \texttt{LISTEN}.
 
+\begin{prototype}{int listen(int sockfd, int backlog)}
+  \begin{errlist}
+  \item \texttt{EBADF} L'argomento \texttt{sockfd} non è un file descriptor
+    valido.
+  \item \texttt{ENOTSOCK} L'argomento \texttt{sockfd} non è un socket.
+  \item \texttt{EOPNOTSUPP} The socket is not of a type that supports the lis­
+    ten operation.
+  \end{errlist}
+\end{prototype}
 
-\section{Una semplice implementazione del servizio \textt{echo} su TCP}
-\label{sec:TCPel_echo_example}
 
 
+\subsection{La funzione \texttt{accept}}
+\label{sec:TCPel_func_accept}
 
 
+\section{Una semplice implementazione del servizio \texttt{echo} su TCP}
+\label{sec:TCPel_echo_example}