X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=elemtcp.tex;h=f59308a68ad1ca52eef5b765c9086c420621e5df;hp=e31736ff6798a7c824528e69bfb94ac18489a54a;hb=ff2d0141751ed62ef56e5bfd226c589311b8b669;hpb=2e096eb5d1df57ce4b887630bdc81526c455b45b diff --git a/elemtcp.tex b/elemtcp.tex index e31736f..f59308a 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -30,8 +30,8 @@ per capire il modello di programmazione ed il funzionamento delle API. In particolare ci concentreremo sulle modalità con le quali il protocollo dà inizio e conclude una connessione; faremo inoltre anche un breve accenno al significato di alcuni dei vari stati che il protocollo assume durante la vita -di una connessione, che possono essere osservati per ciascun socket attivo con -l'uso del programma \cmd{netstat}. +di una connessione, che possono essere osservati per ciascun +socket\index{socket} attivo con l'uso del programma \cmd{netstat}. \subsection{La creazione della connessione: il \textit{three way handshake}} \label{sec:TCPel_conn_cre} @@ -253,10 +253,9 @@ nel campo \textit{State}. Una descrizione completa del funzionamento del protocollo va al di là degli obiettivi di questo libro; un approfondimento sugli aspetti principali si trova in \capref{cha:tcp_protocol}, ma per una trattazione esauriente il -miglior riferimento resta (FIXME citare lo Stevens); qui ci limiteremo a -descrivere brevemente un semplice esempio di connessione e le transizioni che -avvengono nei due casi appena citati (creazione e terminazione della -connessione). +miglior riferimento resta \cite{TCPIll1}; qui ci limiteremo a descrivere +brevemente un semplice esempio di connessione e le transizioni che avvengono +nei due casi appena citati (creazione e terminazione della connessione). In assenza di connessione lo stato del TCP è \texttt{CLOSED}; quando una applicazione esegue una apertura attiva il TCP emette un SYN e lo stato @@ -507,12 +506,15 @@ 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. -Data una connessione TCP si suole chiamare \textit{socket pair} 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 (195.110.112.152:22, 192.84.146.100:20100), identifica univocamente una -connessione su internet. Questo concetto viene di solito esteso anche a UDP, +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 +(195.110.112.152:22, 192.84.146.100:20100), identifica 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 Address}. @@ -642,7 +644,7 @@ Useremo questo schema anche per l'esempio di reimplementazione del servizio \subsection{La funzione \func{bind}} \label{sec:TCPel_func_bind} -La funzione \func{bind} assegna un indirizzo locale ad un socket. È usata +La funzione \funcd{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 è il seguente: @@ -658,7 +660,7 @@ ci si porr \item[\errcode{EBADF}] il file descriptor non è valido. \item[\errcode{EINVAL}] il socket ha già un indirizzo assegnato. \item[\errcode{ENOTSOCK}] il file descriptor non è associato ad un socket. - \item[\errcode{EACCESS}] si è cercato di usare una porta riservata senza + \item[\errcode{EACCES}] si è cercato di usare una porta riservata senza sufficienti privilegi. \end{errlist}} \end{prototype} @@ -737,7 +739,7 @@ con una struttura, perch costante come operando a destra in una assegnazione. Per questo motivo nell'header \file{netinet/in.h} è definita una variabile -\type{in6addr\_any} (dichiarata come \ctyp{extern}, ed inizializzata dal +\const{in6addr\_any} (dichiarata come \direct{extern}, ed inizializzata dal sistema al valore \const{IN6ADRR\_ANY\_INIT}) che permette di effettuare una assegnazione del tipo: @@ -749,7 +751,7 @@ serv_add.sin6_addr = in6addr_any; /* connect from anywhere */ \subsection{La funzione \func{connect}} \label{sec:TCPel_func_connect} -La funzione \func{connect} è usata da un client TCP per stabilire la +La funzione \funcd{connect} è usata da un client TCP per stabilire la connessione con un server TCP, il prototipo della funzione è il seguente: \begin{prototype}{sys/socket.h} {int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t addrlen)} @@ -773,9 +775,9 @@ connessione con un server TCP, il prototipo della funzione \item[\errcode{EAGAIN}] non ci sono più porte locali libere. \item[\errcode{EAFNOSUPPORT}] l'indirizzo non ha una famiglia di indirizzi corretta nel relativo campo. - \item[\errcode{EACCESS, EPERM}] si è tentato di eseguire una connessione ad - un indirizzo broadcast senza che il socket fosse stato abilitato per il - broadcast. + \item[\errcode{EACCES}, \errcode{EPERM}] si è tentato di eseguire una + connessione ad un indirizzo broadcast senza che il socket fosse stato + abilitato per il broadcast. \end{errlist} altri errori possibili sono: \errval{EFAULT}, \errval{EBADF}, \errval{ENOTSOCK}, \errval{EISCONN} e \errval{EADDRINUSE}.} @@ -851,7 +853,7 @@ necessario effettuare una \func{bind}. \subsection{La funzione \func{listen}} \label{sec:TCPel_func_listen} -La funzione \func{listen} è usata per usare un socket in modalità passiva, +La funzione \funcd{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}. In genere si chiama la funzione in @@ -864,20 +866,20 @@ pagina di manuale \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore. I codici di errore restituiti in \var{errno} sono i seguenti: \begin{errlist} - \item[\errcode{EBADF}] l'argomento \var{sockfd} non è un file descriptor + \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor valido. - \item[\errcode{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket. \item[\errcode{EOPNOTSUPP}] il socket è di un tipo che non supporta questa operazione. \end{errlist}} \end{prototype} -La funzione pone il socket specificato da \var{sockfd} in modalità passiva e +La funzione pone il socket specificato da \param{sockfd} in modalità passiva e predispone una coda per le connessioni in arrivo di lunghezza pari a -\var{backlog}. La funzione si può applicare solo a socket di tipo +\param{backlog}. La funzione si può applicare solo a socket di tipo \const{SOCK\_STREAM} o \const{SOCK\_SEQPACKET}. -Il parametro \var{backlog} indica il numero massimo di connessioni pendenti +L'argomento \param{backlog} indica il numero massimo di connessioni pendenti accettate; se esso viene ecceduto il client al momento della richiesta della connessione riceverà un errore di tipo \errcode{ECONNREFUSED}, o se il protocollo, come accade nel caso del TCP, supporta la ritrasmissione, la @@ -908,7 +910,7 @@ processo chiama la funzione \func{accept} (vedi complete è passata al programma, o, se la coda è vuota, il processo viene posto in attesa e risvegliato all'arrivo della prima connessione completa. -Storicamente il valore del parametro \var{backlog} era corrispondente al +Storicamente il valore del parametro \param{backlog} era corrispondente al massimo valore della somma del numero di entrate possibili per ciascuna di dette code. Stevens riporta che BSD ha sempre applicato un fattore di 1.5 al valore, e provvede una tabella con i risultati ottenuti con vari kernel, @@ -922,7 +924,7 @@ indirizzati verso una porta forgiati con indirizzo IP fasullo\footnote{con la perduti e la coda delle connessioni incomplete viene saturata, impedendo di fatto ulteriori connessioni. -Per ovviare a questo il significato del \var{backlog} è stato cambiato a +Per ovviare a questo il significato del \param{backlog} è stato cambiato a indicare la lunghezza della coda delle connessioni complete. La lunghezza della coda delle connessioni incomplete può essere ancora controllata usando la \func{sysctl} o scrivendola direttamente in @@ -930,7 +932,7 @@ la \func{sysctl} o scrivendola direttamente in protezione dei syncookies però (con l'opzione da compilare nel kernel e da attivare usando \file{/proc/sys/net/ipv4/tcp\_syncookies}) questo valore viene ignorato e non esiste più un valore massimo. In ogni caso in Linux il -valore di \var{backlog} viene troncato ad un massimo di \const{SOMAXCONN} +valore di \param{backlog} viene troncato ad un massimo di \const{SOMAXCONN} se è superiore a detta costante (che di default vale 128). La scelta storica per il valore di questo parametro è di 5, e alcuni vecchi @@ -965,37 +967,33 @@ trasparente dal protocollo TCP. \subsection{La funzione \func{accept}} \label{sec:TCPel_func_accept} -La funzione \func{accept} è chiamata da un server TCP per gestire la +La funzione \funcd{accept} è chiamata da un server TCP per gestire la connessione una volta che sia stato completato il three way handshake, 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: \begin{prototype}{sys/socket.h} {int accept(int sockfd, struct sockaddr *addr, socklen\_t *addrlen)} - Estrae la prima connessione relativa al socket \var{sockfd} - in attesa sulla coda delle connessioni complete, che associa ad nuovo socket - con le stesse caratteristiche di \var{sockfd} (restituito dalla funzione - stessa). Il socket originale non viene toccato. Nella struttura - \var{addr} e nella variabile \var{addrlen} vengono restituiti - indirizzo e relativa lunghezza del client che si è connesso. + Accetta una connessione sul socket specificato. + \bodydesc{La funzione restituisce un numero di socket descriptor positivo in caso di successo e -1 in caso di errore, nel qual caso la variabile \var{errno} viene impostata ai seguenti valori: \begin{errlist} - \item[\errcode{EBADF}] l'argomento \var{sockfd} non è un file descriptor + \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor valido. - \item[\errcode{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket. \item[\errcode{EOPNOTSUPP}] il socket è di un tipo che non supporta questa operazione. \item[\errcode{EAGAIN} o \errcode{EWOULDBLOCK}] il socket è stato impostato come non bloccante (vedi \secref{sec:file_noblocking}), e non ci sono connessioni in attesa di essere accettate. \item[\errcode{EPERM}] Le regole del firewall non consentono la connessione. - \item[\errcode{ENOBUFS, ENOMEM}] questo spesso significa che l'allocazione - della memoria è limitata dai limiti sui buffer dei socket, non dalla - memoria di sistema. + \item[\errcode{ENOBUFS}, \errcode{ENOMEM}] questo spesso significa che + l'allocazione della memoria è limitata dai limiti sui buffer dei socket, + non dalla memoria di sistema. \end{errlist} Inoltre possono essere restituiti gli errori di rete relativi al nuovo socket come: \errval{EMFILE}, \errval{EINVAL}, \errval{ENOSR}, @@ -1004,6 +1002,13 @@ viene messo in attesa. Il prototipo della funzione \errval{ERESTARTSYS}.} \end{prototype} +Estrae la prima connessione relativa al socket \param{sockfd} in attesa sulla +coda delle connessioni complete, che associa ad nuovo socket con le stesse +caratteristiche di \param{sockfd} (restituito dalla funzione stessa). Il +socket originale non viene toccato. Nella struttura \param{addr} e nella +variabile \param{addrlen} vengono restituiti indirizzo e relativa lunghezza del +client che si è connesso. + La funzione può essere usata solo con socket che supportino la connessione (cioè di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET} o \const{SOCK\_RDM}). Per alcuni protocolli che richiedono una conferma @@ -1021,20 +1026,20 @@ socket flag come \const{O\_NONBLOCK}, che devono essere rispecificati volta volta, questo è un comportamento diverso rispetto a quanto accade con BSD e deve essere tenuto in conto per scrivere programmi portabili. -I due argomenti \var{cliaddr} e \var{addrlen} (si noti che quest'ultimo -è passato per indirizzo per avere indietro il valore) sono usati per ottenere +I due argomenti \param{cliaddr} e \param{addrlen} (si noti che quest'ultimo è +passato per indirizzo per avere indietro il valore) sono usati per ottenere l'indirizzo del client da cui proviene la connessione. Prima della chiamata -\var{addrlen} deve essere inizializzato alle dimensioni della struttura il -cui indirizzo è passato come argomento in \var{cliaddr}, al ritorno della -funzione \var{addrlen} conterrà il numero di byte scritti dentro -\var{cliaddr}. Se questa informazione non interessa basterà inizializzare a +\param{addrlen} deve essere inizializzato alle dimensioni della struttura il +cui indirizzo è passato come argomento in \param{cliaddr}, al ritorno della +funzione \param{addrlen} conterrà il numero di byte scritti dentro +\param{cliaddr}. Se questa informazione non interessa basterà inizializzare a \val{NULL} detti puntatori. Se la funzione ha successo restituisce il descrittore di un nuovo socket creato dal kernel (detto \textit{connected socket}) a cui viene associata la prima connessione completa (estratta dalla relativa coda, vedi \secref{sec:TCPel_func_listen}) che il client TCP ha effettuato verso il -socket \var{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello +socket \param{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello creato all'inizio e messo in ascolto con \func{listen}, e non viene toccato dalla funzione. Se non ci sono connessioni pendenti da accettare la funzione mette in attesa il processo\footnote{a meno che non si sia imopstato il socket @@ -1217,10 +1222,9 @@ chiusa. \subsection{Le funzioni \func{getsockname} e \func{getpeername}} \label{sec:TCPel_get_names} -Queste due funzioni vengono usate per ottenere la socket pair associata ad un -certo socket; la prima restituisce l'indirizzo locale, la seconda quello -remoto. - +Queste due funzioni vengono usate per ottenere i dati realtivi alla socket +pair associata ad un certo socket; la prima è \funcd{getsockname} e +restituisce l'indirizzo locale; il suo prototipo è: \begin{prototype}{sys/socket.h} {int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)} Legge l'indirizzo locale del socket \param{sockfd} nella struttura @@ -1229,28 +1233,30 @@ remoto. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore. I codici di errore restituiti in \var{errno} sono i seguenti: \begin{errlist} - \item[\errcode{EBADF}] l'argomento \var{sockfd} non è un file descriptor + \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor valido. - \item[\errcode{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket. \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per eseguire l'operazione. - \item[\errcode{EFAULT}] l'argomento \var{name} punta al di fuori dello + \item[\errcode{EFAULT}] l'argomento \param{name} punta al di fuori dello spazio di indirizzi del processo. \end{errlist}} \end{prototype} -La funzione \func{getsockname} si usa tutte le volte che si vuole avere -l'indirizzo locale di un socket; ad esempio può essere usata da un client (che -usualmente non chiama \func{bind}) per ottenere numero IP e porta locale -associati al socket restituito da una \func{connect}, o da un server che ha -chiamato \func{bind} su un socket usando 0 come porta locale per ottenere il -numero di porta effimera assegnato dal kernel. +La funzione si usa tutte le volte che si vuole avere l'indirizzo locale di un +socket; ad esempio può essere usata da un client (che usualmente non chiama +\func{bind}) per ottenere numero IP e porta locale associati al socket +restituito da una \func{connect}, o da un server che ha chiamato \func{bind} +su un socket usando 0 come porta locale per ottenere il numero di porta +effimera assegnato dal kernel. Inoltre quando un server esegue una \func{bind} su un indirizzo generico, se chiamata dopo il completamento di una connessione sul socket restituito da \func{accept}, restituisce l'indirizzo locale che il kernel ha assegnato a quella connessione. +Tutte le volte che si vuole avere l'indirizzo remoto di un socket si usa la +funzione \funcd{getpeername}, il cui prototipo è: \begin{prototype}{sys/socket.h} {int getpeername(int sockfd, struct sockaddr * name, socklen\_t * namelen)} Legge l'indirizzo remoto del socket \param{sockfd} nella struttura @@ -1259,21 +1265,17 @@ quella connessione. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore. I codici di errore restituiti in \var{errno} sono i seguenti: \begin{errlist} - \item[\errcode{EBADF}] l'argomento \var{sockfd} non è un file descriptor + \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor valido. - \item[\errcode{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket. \item[\errcode{ENOTCONN}] il socket non è connesso. \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per eseguire l'operazione. - \item[\errcode{EFAULT}] l'argomento \var{name} punta al di fuori dello + \item[\errcode{EFAULT}] l'argomento \param{name} punta al di fuori dello spazio di indirizzi del processo. \end{errlist}} \end{prototype} - -La funzione \func{getpeername} si usa tutte le volte che si vuole avere -l'indirizzo remoto di un socket. - Ci si può chiedere a cosa serva questa funzione dato che dal lato client l'indirizzo remoto è sempre noto quando si esegue la \func{connect} mentre dal lato server si possono usare, come si è fatto nell'esempio precedente, i