X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=elemtcp.tex;h=964dd4f16f5cc1c0539b9338093392ae75c5905a;hp=effafc390a905613132ba6fac9bc933a45a56072;hb=f1b2cf6ae09fb598a0b44719644ffaa94c2864f3;hpb=e20a546af590a50e7ac47f68f6c7d4648bb4f31a diff --git a/elemtcp.tex b/elemtcp.tex index effafc3..964dd4f 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -44,7 +44,7 @@ creazione di una connessione \func{connect}, attraverso un procedimento che viene chiamato \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\footnote{Si ricordi che il segmento è l'unità elementare di + segmento SYN,\footnote{Si ricordi che il segmento è l'unità elementare di dati trasmessa dal protocollo TCP al livello superiore; tutti i segmenti hanno un header che contiene le informazioni che servono allo \textit{stack TCP} (così viene di solito chiamata la parte del kernel che @@ -52,7 +52,7 @@ creazione di una connessione 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 \capref{cha:tcp_protocol})}, in + segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol}).} in sostanza viene inviato al server un pacchetto IP che contiene solo gli header IP e TCP (con il numero di sequenza iniziale e il flag SYN) e le opzioni di TCP. @@ -60,8 +60,8 @@ creazione di una connessione \item il server deve dare ricevuto (l'\textit{acknowledge}) del SYN del 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 entrambi i flag SYN ACK e sono - settati. + ritrasmettendo un singolo segmento in cui sono impostati entrambi i flag SYN + 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 @@ -100,7 +100,7 @@ segmento. Il numero di sequenza di ciascun segmento viene calcolato a partire da un \textsl{numero di sequenza iniziale} generato in maniera casuale del kernel all'inizio della connessione e trasmesso con il SYN; l'acknowledgement di -ciascun segmento viene effettuato dall'altro capo della connessione settando +ciascun segmento viene effettuato dall'altro capo della connessione impostando il flag ACK e restituendo nell'apposito campo dell'header un \textit{acknowledge number}) pari al numero di sequenza che il ricevente si aspetta di ricevere con il pacchetto successivo; dato che il primo pacchetto @@ -128,20 +128,20 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: \textsl{finestra annunciata} (\textit{advertized window}) 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 (anche se Linux usa come massimo 32767 - per evitare problemi con alcuni stack bacati che usano l'aritmetica con - segno per implementare lo stack TCP); ma alcuni tipi di connessione come - quelle ad alta velocità (sopra i 45Mbits/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 questa opzione che indica un fattore di scala da applicare al valore - della finestra annunciata\footnote{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 - connessione riconosca esplicitamente l'opzione inserendola anche lui nel - suo SYN di risposta dell'apertura della connessione} per la connessione - corrente (espresso come numero di bit cui shiftare a sinistra il valore - della finestra annunciata inserito nel pacchetto). + indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767 per + evitare problemi con alcuni stack bacati che usano l'aritmetica con segno + per implementare lo stack TCP); ma alcuni tipi di connessione come quelle ad + alta velocità (sopra i 45Mbits/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 questa + opzione che indica un fattore di scala da applicare al valore della finestra + annunciata\footnote{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 connessione + riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di + risposta dell'apertura della connessione.} per la connessione corrente + (espresso come numero di bit cui shiftare a sinistra il valore della + finestra annunciata inserito nel pacchetto). \item \textit{timestamp option}, è anche questa una nuova opzione necessaria per le connessioni ad alta velocità per evitare possibili corruzioni di dati @@ -640,17 +640,17 @@ ci si porr a \func{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 \secref{sec:sock_sockaddr}. - - La funzione restituisce zero in caso di successo e -1 per un errore; in caso - di errore la variabile \var{errno} viene settata secondo i seguenti - codici di errore: + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore; in caso di errore la variabile \var{errno} viene impostata secondo + i seguenti codici di errore: \begin{errlist} - \item \macro{EBADF} il file descriptor non è valido. - \item \macro{EINVAL} il socket ha già un indirizzo assegnato. - \item \macro{ENOTSOCK} il file descriptor non è associato ad un socket. - \item \macro{EACCESS} si è cercato di usare una porta riservata senza + \item[\macro{EBADF}] il file descriptor non è valido. + \item[\macro{EINVAL}] il socket ha già un indirizzo assegnato. + \item[\macro{ENOTSOCK}] il file descriptor non è associato ad un socket. + \item[\macro{EACCESS}] si è cercato di usare una porta riservata senza sufficienti privilegi. - \end{errlist} + \end{errlist}} \end{prototype} Con il TCP la chiamata \func{bind} permette di specificare l'indirizzo, la @@ -662,7 +662,7 @@ per il server\footnote{un'eccezione a tutto ci 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 + su cui si trova il server.} che in genere viene identificato dalla porta su cui risponde. Con \func{bind} si può assegnare un IP specifico ad un socket, purché questo @@ -686,7 +686,7 @@ un'assegnazione immediata del tipo: \footnotesize \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} - serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ + serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ \end{lstlisting} \normalsize @@ -703,12 +703,13 @@ consente l'uso di una struttura costante come operando a destra in una assegnazione. Per questo nell'header \file{netinet/in.h} è definita una variabile -\type{in6addr\_any} (dichiarata come \type{extern}, ed inizializzata dal +\type{in6addr\_any} (dichiarata come \ctyp{extern}, ed inizializzata dal sistema al valore \macro{IN6ADRR\_ANY\_INIT}) che permette di effettuare una assegnazione del tipo: + \footnotesize \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} - serv_add.sin6_addr = in6addr_any; /* connect from anywhere */ + serv_add.sin6_addr = in6addr_any; /* connect from anywhere */ \end{lstlisting} \normalsize @@ -725,30 +726,30 @@ connessione con un server TCP, il prototipo della funzione a \func{socket}, mentre il secondo e terzo argomento sono rispettivamente l'indirizzo e la dimensione della struttura che contiene l'indirizzo del socket, già descritta in \secref{sec:sock_sockaddr}. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore la variabile \var{errno} viene settata secondo i seguenti - codici di errore: + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, in caso di errore la variabile \var{errno} viene impostata secondo + i seguenti codici di errore: \begin{errlist} - \item \macro{EISCONN} il socket è già connesso. - \item \macro{ECONNREFUSED} non c'è nessuno in ascolto sull'indirizzo remoto. - \item \macro{ETIMEDOUT} si è avuto timeout durante il tentativo di + \item[\macro{ECONNREFUSED}] non c'è nessuno in ascolto sull'indirizzo remoto. + \item[\macro{ETIMEDOUT}] si è avuto timeout durante il tentativo di connessione. - \item \macro{ENETUNREACH} la rete non è raggiungibile. - \item \macro{EADDRINUSE} l'indirizzo locale è in uso. - \item \macro{EINPROGRESS} il socket è non bloccante e la connessione non - può essere conclusa immediatamente. - \item \macro{EALREADY} il socket è non bloccante e un tentativo precedente - di connessione non si è ancora concluso. - \item \macro{EAGAIN} non ci sono più porte locali libere. - \item \macro{EAFNOSUPPORT} l'indirizzo non ha una famiglia di indirizzi + \item[\macro{ENETUNREACH}] la rete non è raggiungibile. + \item[\macro{EINPROGRESS}] il socket è non bloccante (vedi + \secref{sec:file_noblocking}) e la connessione non può essere conclusa + immediatamente. + \item[\macro{EALREADY}] il socket è non bloccante (vedi + \secref{sec:file_noblocking}) e un tentativo precedente di connessione non + si è ancora concluso. + \item[\macro{EAGAIN}] non ci sono più porte locali libere. + \item[\macro{EAFNOSUPPORT}] l'indirizzo non ha una famiglia di indirizzi corretta nel relativo campo. - \item \macro{EACCESS, EPERM} si è tentato di eseguire una connessione ad un + \item[\macro{EACCESS, 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: \macro{EFAULT}, \macro{EBADF}, - \macro{ENOTSOCK}. + \macro{ENOTSOCK}, \macro{EISCONN} e \macro{EADDRINUSE}.} \end{prototype} La struttura dell'indirizzo deve essere inizializzata con l'indirizzo IP e il @@ -770,11 +771,11 @@ seguenti: 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 \func{sysctl} che attraverso il filesystem \file{/proc} scrivendo il valore - voluto in \file{/proc/sys/net/ipv4/tcp\_syn\_retries}. Il valore di default + 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 settabili via /proc stanno in +% 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'è @@ -822,22 +823,22 @@ sostanza l'effetto della funzione \texttt{CLOSED} a quello \texttt{LISTEN}. In genere si chiama la funzione in un server dopo le chiamate a \func{socket} e \func{bind} e prima della chiamata ad \func{accept}. Il prototipo della funzione come definito dalla -man page è: +pagina di manuale è: \begin{prototype}{sys/socket.h}{int listen(int sockfd, int backlog)} La funzione pone il socket specificato da \var{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 \macro{SOCK\_STREAM} o \macro{SOCK\_SEQPACKET}. - - 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: + + \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 \macro{EBADF} l'argomento \var{sockfd} non è un file descriptor + \item[\macro{EBADF}] l'argomento \var{sockfd} non è un file descriptor valido. - \item \macro{ENOTSOCK} l'argomento \var{sockfd} non è un socket. - \item \macro{EOPNOTSUPP} il socket è di un tipo che non supporta questa + \item[\macro{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\macro{EOPNOTSUPP}] il socket è di un tipo che non supporta questa operazione. - \end{errlist} + \end{errlist}} \end{prototype} @@ -878,11 +879,11 @@ 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, compreso Linux 2.0, che mostrano le differenze fra diverse implementazioni. -In Linux il significato di questo valore è cambiato a partire dal kernel -2.2 per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa +In Linux il significato di questo valore è cambiato a partire dal kernel 2.2 +per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa sull'emissione da parte dell'attaccante di un grande numero di pacchetti SYN indirizzati verso una porta forgiati con indirizzo IP fasullo\footnote{con la - tecnica che viene detta \textit{ip spoofing}} così che i SYN$+$ACK vanno + tecnica che viene detta \textit{ip spoofing}.} così che i SYN$+$ACK vanno perduti e la coda delle connessioni incomplete viene saturata, impedendo di fatto ulteriori connessioni. @@ -936,27 +937,28 @@ 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)} - La funzione estrae la prima connessione relativa al socket \var{sockfd} + 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. - 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 settata ai seguenti valori: + \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 \macro{EBADF} l'argomento \var{sockfd} non è un file descriptor + \item[\macro{EBADF}] l'argomento \var{sockfd} non è un file descriptor valido. - \item \macro{ENOTSOCK} l'argomento \var{sockfd} non è un socket. - \item \macro{EOPNOTSUPP} il socket è di un tipo che non supporta questa + \item[\macro{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\macro{EOPNOTSUPP}] il socket è di un tipo che non supporta questa operazione. - \item \macro{EAGAIN} o \macro{EWOULDBLOCK} il socket è stato settato come - non bloccante, e non ci sono connessioni in attesa di essere accettate. - \item \macro{EPERM} Le regole del firewall non consentono la connessione. - \item \macro{ENOBUFS, ENOMEM} . Questo spesso significa che l'allocazione + \item[\macro{EAGAIN} o \macro{EWOULDBLOCK}] il socket è stato impostato come + non bloccante (vedi \secref{sec:file_noblocking}), e non ci sono + connessioni in attesa di essere accettate. + \item[\macro{EPERM}] Le regole del firewall non consentono la connessione. + \item[\macro{ENOBUFS, ENOMEM}] questo spesso significa che l'allocazione della memoria è limitata dai limiti sui buffer dei socket, non dalla memoria di sistema. \end{errlist} @@ -964,7 +966,7 @@ viene messo in attesa. Il prototipo della funzione socket come: \macro{EMFILE}, \macro{EINVAL}, \macro{ENOSR}, \macro{ENOBUFS}, \macro{EFAULT}, \macro{EPERM}, \macro{ECONNABORTED}, \macro{ESOCKTNOSUPPORT}, \macro{EPROTONOSUPPORT}, \macro{ETIMEDOUT}, - \macro{ERESTARTSYS}. + \macro{ERESTARTSYS}.} \end{prototype} La funzione può essere usata solo con socket che supportino la connessione @@ -997,14 +999,14 @@ 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 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 settato il socket per essere - non-bloccante, nel qual caso ritorna con l'errore \func{EAGAIN}, - torneremo su questa modalità di operazione in \secref{sec:xxx_sock_noblock}} -fintanto che non ne arriva una. +socket \var{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 + per essere non bloccante (vedi \secref{sec:file_noblocking}), nel qual caso + ritorna con l'errore \macro{EAGAIN}. Torneremo su questa modalità di + operazione in \secref{sec:xxx_sock_noblock}.} fintanto che non ne arriva +una. Il meccanismo di funzionamento di \func{accept} è essenziale per capire il funzionamento di un server: in generale infatti c'è sempre un solo socket in @@ -1185,19 +1187,21 @@ certo socket; la prima restituisce l'indirizzo locale, la seconda quello remoto. \begin{prototype}{sys/socket.h} -{int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)} + {int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)} + Legge l'indirizzo locale del socket \param{sockfd} nella struttura + \param{name}. - 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: +\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 \macro{EBADF} l'argomento \var{sockfd} non è un file descriptor + \item[\macro{EBADF}] l'argomento \var{sockfd} non è un file descriptor valido. - \item \macro{ENOTSOCK} l'argomento \var{sockfd} non è un socket. - \item \macro{ENOBUFS} non ci sono risorse sufficienti nel sistema per + \item[\macro{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\macro{ENOBUFS}] non ci sono risorse sufficienti nel sistema per eseguire l'operazione. - \item \macro{EFAULT} l'argomento \var{name} punta al di fuori dello + \item[\macro{EFAULT}] l'argomento \var{name} punta al di fuori dello spazio di indirizzi del processo. - \end{errlist} + \end{errlist}} \end{prototype} La funzione \func{getsockname} si usa tutte le volte che si vuole avere @@ -1213,20 +1217,22 @@ chiamata dopo il completamento di una connessione sul socket restituito da quella connessione. \begin{prototype}{sys/socket.h} -{int getpeername(int sockfd, struct sockaddr * name, socklen\_t * namelen)} - - 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: + {int getpeername(int sockfd, struct sockaddr * name, socklen\_t * namelen)} + Legge l'indirizzo remoto del socket \param{sockfd} nella struttura + \param{name}. + + \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 \macro{EBADF} l'argomento \var{sockfd} non è un file descriptor + \item[\macro{EBADF}] l'argomento \var{sockfd} non è un file descriptor valido. - \item \macro{ENOTSOCK} l'argomento \var{sockfd} non è un socket. - \item \macro{ENOTCONN} il socket non è connesso. - \item \macro{ENOBUFS} non ci sono risorse sufficienti nel sistema per + \item[\macro{ENOTSOCK}] l'argomento \var{sockfd} non è un socket. + \item[\macro{ENOTCONN}] il socket non è connesso. + \item[\macro{ENOBUFS}] non ci sono risorse sufficienti nel sistema per eseguire l'operazione. - \item \macro{EFAULT} l'argomento \var{name} punta al di fuori dello + \item[\macro{EFAULT}] l'argomento \var{name} punta al di fuori dello spazio di indirizzi del processo. - \end{errlist} + \end{errlist}} \end{prototype} @@ -1256,10 +1262,15 @@ connesso (\cmd{inetd} ad esempio fa sempre in modo che i file descriptor 0, 1 e 2 corrispondano al socket connesso) quest'ultimo potrà usare la funzione \func{getpeername} per determinare l'indirizzo remoto del client. -Infine è da chiarire (si legga la man page) che come per \func{accept} il -terzo parametro che è specificato dallo standard POSIX 1003.1g come di tipo -\type{socklen\_t *} in realtà deve sempre corrispondere ad un \type{int *} -come prima dello standard perché tutte le implementazioni dei socket BSD fanno -questa assunzione. +Infine è da chiarire (si legga la pagina di manuale) che, come per +\func{accept}, il terzo parametro, 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 +socket BSD fanno questa assunzione. + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: