From de137402ded9a730854f908315767d73c5308d9d Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Fri, 28 Oct 2016 18:28:18 +0000 Subject: [PATCH] Correzioni e miglioramenti tipografici --- filedir.tex | 70 +++++----- fileio.tex | 24 ++-- intro.tex | 8 +- ipc.tex | 2 +- tcpsock.tex | 383 +++++++++++++++++++++++++++------------------------- 5 files changed, 253 insertions(+), 234 deletions(-) diff --git a/filedir.tex b/filedir.tex index f428ba8..3e6bad3 100644 --- a/filedir.tex +++ b/filedir.tex @@ -345,11 +345,11 @@ Il VFS realizza la quasi totalità delle operazioni relative ai file grazie alle funzioni presenti nelle due strutture \kstruct{inode\_operation} e \kstruct{file\_operation}. Ovviamente non è detto che tutte le operazioni possibili siano poi disponibili in tutti i casi, ad esempio \code{llseek} non -sarà presente per un dispositivo come la porta seriale o per una fifo, mentre -sui file del filesystem \texttt{vfat} non saranno disponibili i permessi, ma -resta il fatto che grazie al VFS le \textit{system call} per le operazioni sui -file possono restare sempre le stesse nonostante le enormi differenze che -possono esserci negli oggetti a cui si applicano. +sarà presente per un dispositivo come la porta seriale o per una +\textit{fifo}, mentre sui file del filesystem \texttt{vfat} non saranno +disponibili i permessi, ma resta il fatto che grazie al VFS le \textit{system + call} per le operazioni sui file possono restare sempre le stesse nonostante +le enormi differenze che possono esserci negli oggetti a cui si applicano. \itindend{Virtual~File~System~(VFS)} @@ -1692,11 +1692,11 @@ La funzione elimina il nome specificato dall'argomento \param{pathname} nella directory che lo contiene e decrementa il numero di riferimenti nel relativo \textit{inode}.\footnote{come per \func{link} queste due operazioni sono effettuate all'interno della \textit{system call} in maniera atomica.} Nel -caso di socket, fifo o file di dispositivo rimuove il nome, ma come per i file -normali i processi che hanno aperto uno di questi oggetti possono continuare -ad utilizzarli. Nel caso di cancellazione di un collegamento simbolico, che -consiste solo nel rimando ad un altro file, questo viene immediatamente -eliminato. +caso di socket, \textit{fifo} o file di dispositivo rimuove il nome, ma come +per i file normali i processi che hanno aperto uno di questi oggetti possono +continuare ad utilizzarli. Nel caso di cancellazione di un collegamento +simbolico, che consiste solo nel rimando ad un altro file, questo viene +immediatamente eliminato. Per cancellare una voce in una directory è necessario avere il permesso di scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e @@ -2211,8 +2211,8 @@ sez.~\ref{sec:sys_file_limits}) più un ulteriore carattere per la terminazione della stringa. Per quanto riguarda il significato dei campi opzionali, il campo \var{d\_type} -indica il tipo di file (se fifo, directory, collegamento simbolico, ecc.), e -consente di evitare una successiva chiamata a \func{lstat} (vedi +indica il tipo di file (se \textit{fifo}, directory, collegamento simbolico, +ecc.), e consente di evitare una successiva chiamata a \func{lstat} (vedi sez.~\ref{sec:file_stat}) per determinarlo. I suoi possibili valori sono riportati in tab.~\ref{tab:file_dtype_macro}. Si tenga presente che questo valore è disponibile solo per i filesystem che ne supportano la restituzione @@ -2234,7 +2234,7 @@ valore è disponibile solo per i filesystem che ne supportano la restituzione \constd{DT\_REG} & File normale.\\ \constd{DT\_DIR} & Directory.\\ \constd{DT\_LNK} & Collegamento simbolico.\\ - \constd{DT\_FIFO} & Fifo.\\ + \constd{DT\_FIFO} & \textit{Fifo}.\\ \constd{DT\_SOCK} & Socket.\\ \constd{DT\_CHR} & Dispositivo a caratteri.\\ \constd{DT\_BLK} & Dispositivo a blocchi.\\ @@ -2643,7 +2643,7 @@ ha il permesso di attraversamento alla directory specificata da \param{fd}. Finora abbiamo parlato esclusivamente di file, directory e collegamenti simbolici, ma in sez.~\ref{sec:file_file_types} abbiamo visto che il sistema prevede anche degli altri tipi di file, che in genere vanno sotto il nome -generico di \textsl{file speciali}, come i file di dispositivo, le fifo ed i +generico di \textsl{file speciali}, come i file di dispositivo, le \textit{fifo} ed i socket. La manipolazione delle caratteristiche di questi file speciali, il cambiamento @@ -2666,7 +2666,7 @@ funzione di sistema \funcd{mknod}, il cui prototipo è: \item[\errcode{EEXIST}] \param{pathname} esiste già o è un collegamento simbolico. \item[\errcode{EINVAL}] il valore di \param{mode} non indica un file, una - fifo, un socket o un dispositivo. + \textit{fifo}, un socket o un dispositivo. \item[\errcode{EPERM}] non si hanno privilegi sufficienti a creare l'\texttt{inode}, o il filesystem su cui si è cercato di creare \param{pathname} non supporta l'operazione. @@ -2689,8 +2689,8 @@ Per il tipo di file può essere specificato solo uno fra i seguenti valori: \const{S\_IFREG} per un file regolare (che sarà creato vuoto), \const{S\_IFBLK} per un dispositivo a blocchi, \const{S\_IFCHR} per un dispositivo a caratteri, \const{S\_IFSOCK} per un socket e \const{S\_IFIFO} -per una fifo;\footnote{con Linux la funzione non può essere usata per creare - directory o collegamenti simbolici, si dovranno usare le funzioni +per una \textit{fifo};\footnote{con Linux la funzione non può essere usata per + creare directory o collegamenti simbolici, si dovranno usare le funzioni \func{mkdir} e \func{symlink} a questo dedicate.} un valore diverso comporterà l'errore \errcode{EINVAL}. Inoltre \param{pathname} non deve esistere, neanche come collegamento simbolico. @@ -2705,9 +2705,9 @@ dispositivo usando questa funzione (il processo deve avere la capacità mentre è presente in SVr4 e 4.4BSD, ma esistono differenze nei comportamenti e nei codici di errore, tanto che questa è stata introdotta in POSIX.1-2001 con una nota che la definisce portabile solo quando viene usata per creare - delle fifo, ma comunque deprecata essendo utilizzabile a tale scopo la - specifica \func{mkfifo}.} l'uso per la creazione di un file ordinario, di -una fifo o di un socket è consentito anche agli utenti normali. + delle \textit{fifo}, ma comunque deprecata essendo utilizzabile a tale scopo + la specifica \func{mkfifo}.} l'uso per la creazione di un file ordinario, di +una \textit{fifo} o di un socket è consentito anche agli utenti normali. I nuovi \textit{inode} creati con \func{mknod} apparterranno al proprietario e al gruppo del processo (usando \ids{UID} e \ids{GID} del gruppo effettivo) che @@ -2792,17 +2792,17 @@ macro \macro{makedev}: Dato che la funzione di sistema \func{mknod} presenta diverse varianti nei vari sistemi unix-like, lo standard POSIX.1-2001 la dichiara portabile solo in -caso di creazione delle fifo, ma anche in questo caso alcune combinazioni -degli argomenti restano non specificate, per cui nello stesso standard è stata -introdotta una funzione specifica per creare una fifo deprecando l'uso di -\func{mknod} a tale riguardo. La funzione è \funcd{mkfifo} ed il suo -prototipo è: +caso di creazione delle \textit{fifo}, ma anche in questo caso alcune +combinazioni degli argomenti restano non specificate, per cui nello stesso +standard è stata introdotta una funzione specifica per creare una +\textit{fifo} deprecando l'uso di \func{mknod} a tale riguardo. La funzione è +\funcd{mkfifo} ed il suo prototipo è: \begin{funcproto}{ \fhead{sys/types.h} \fhead{sys/stat.h} \fdecl{int mkfifo(const char *pathname, mode\_t mode)} -\fdesc{Crea una fifo.} +\fdesc{Crea una \textit{fifo}.} } {La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà \errval{EACCES}, \errval{EEXIST}, @@ -2810,11 +2810,11 @@ prototipo è: \errval{EROFS} nel loro significato generico.} \end{funcproto} -La funzione crea la fifo \param{pathname} con i permessi \param{mode}. Come -per \func{mknod} il file \param{pathname} non deve esistere (neanche come -collegamento simbolico); al solito i permessi specificati da \param{mode} -vengono modificati dal valore di \textit{umask} (vedi -sez.~\ref{sec:file_perm_management}). +La funzione crea la \textit{fifo} \param{pathname} con i +permessi \param{mode}. Come per \func{mknod} il file \param{pathname} non deve +esistere (neanche come collegamento simbolico); al solito i permessi +specificati da \param{mode} vengono modificati dal valore di \textit{umask} +(vedi sez.~\ref{sec:file_perm_management}). \index{file!speciali|)} @@ -3193,7 +3193,7 @@ tipo di file in maniera standardizzata. \macrod{S\_ISDIR}\texttt{(m)} & Directory.\\ \macrod{S\_ISCHR}\texttt{(m)} & Dispositivo a caratteri.\\ \macrod{S\_ISBLK}\texttt{(m)} & Dispositivo a blocchi.\\ - \macrod{S\_ISFIFO}\texttt{(m)} & Fifo.\\ + \macrod{S\_ISFIFO}\texttt{(m)} & \textit{Fifo}.\\ \macrod{S\_ISLNK}\texttt{(m)} & Collegamento simbolico.\\ \macrod{S\_ISSOCK}\texttt{(m)} & Socket.\\ \hline @@ -3226,7 +3226,7 @@ come argomento il valore di \var{st\_mode}. \constd{S\_IFBLK} & 0060000 & Dispositivo a blocchi.\\ \constd{S\_IFDIR} & 0040000 & Directory.\\ \constd{S\_IFCHR} & 0020000 & Dispositivo a caratteri.\\ - \constd{S\_IFIFO} & 0010000 & Fifo.\\ + \constd{S\_IFIFO} & 0010000 & \textit{Fifo}.\\ \hline \constd{S\_ISUID} & 0004000 & Set user ID (\acr{suid}) bit, vedi sez.~\ref{sec:file_special_perm}).\\ @@ -3293,7 +3293,7 @@ Abbiamo visto in fig.~\ref{fig:file_stat_struct} che campo \var{st\_size} di una struttura \struct{stat} contiene la dimensione del file in byte. Questo però è vero solo se si tratta di un file regolare, mentre nel caso di un collegamento simbolico la dimensione è quella del \textit{pathname} che il -collegamento stesso contiene, infine per le fifo ed i file di dispositivo +collegamento stesso contiene, infine per le \textit{fifo} ed i file di dispositivo questo campo è sempre nullo. Il campo \var{st\_blocks} invece definisce la lunghezza del file in blocchi di @@ -4869,7 +4869,7 @@ tab.~\ref{tab:extended_attribute_class}, si hanno i seguenti casi: due casi hanno a che fare con il contenuto del file, e nella discussione relativa all'uso degli \textit{extended user attributes} nessuno è mai stato capace di indicare una qualche forma sensata di utilizzo degli stessi per - collegamenti simbolici o file di dispositivo, e neanche per le fifo o i + collegamenti simbolici o file di dispositivo, e neanche per le \textit{fifo} o i socket. Per questo motivo essi sono stati completamente disabilitati per tutto ciò che non sia un file regolare o una directory.\footnote{si può verificare la semantica adottata consultando il file \texttt{fs/xattr.c} diff --git a/fileio.tex b/fileio.tex index 2c11011..3091504 100644 --- a/fileio.tex +++ b/fileio.tex @@ -262,9 +262,9 @@ corrispondente,\footnote{è \func{open} che alloca \kstruct{file}, la inserisce \item[\errcode{ENOTDIR}] si è specificato \const{O\_DIRECTORY} e \param{pathname} non è una directory. \item[\errcode{ENXIO}] si sono impostati \const{O\_NONBLOCK} o - \const{O\_WRONLY} ed il file è una fifo che non viene letta da nessun - processo o \param{pathname} è un file di dispositivo ma il dispositivo è - assente. + \const{O\_WRONLY} ed il file è una \textit{fifo} che non viene letta da + nessun processo o \param{pathname} è un file di dispositivo ma il + dispositivo è assente. \item[\errcode{EPERM}] si è specificato \const{O\_NOATIME} e non si è né amministratori né proprietari del file. \item[\errcode{ETXTBSY}] si è cercato di accedere in scrittura all'immagine @@ -407,7 +407,7 @@ sez.~\ref{sec:file_fcntl_ioctl}). serve ad evitare dei possibili \itindex{Denial~of~Service~(DoS)} \textit{DoS}\footnotemark quando \func{opendir} - viene chiamata su una fifo o su un dispositivo + viene chiamata su una \textit{fifo} o su un dispositivo associato ad una unità a nastri. Non viene usato al di fuori dell'implementazione di \func{opendir}, ed è utilizzabile soltanto se si è @@ -439,7 +439,7 @@ sez.~\ref{sec:file_fcntl_ioctl}). la macro \macro{\_GNU\_SOURCE}.\\ \constd{O\_TRUNC} & Se usato su un file di dati aperto in scrittura, ne tronca la lunghezza a zero; con un terminale o - una fifo viene ignorato, negli altri casi il + una \textit{fifo} viene ignorato, negli altri casi il comportamento non è specificato.\\ \hline \end{tabular} @@ -512,7 +512,7 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il tutte le volte che il file è pronto per le operazioni di lettura o scrittura. Questo flag si può usare solo terminali, pseudo-terminali e socket - e, a partire dal kernel 2.6, anche sulle fifo. Per + e, a partire dal kernel 2.6, anche sulle \textit{fifo}. Per un bug dell'implementazione non è opportuno usarlo in fase di apertura del file, deve invece essere attivato successivamente con @@ -549,7 +549,7 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il blocco delle stesse in attesa di una successiva possibilità di esecuzione come avviene normalmente. Questa modalità ha senso solo per le - fifo, vedi sez.~\ref{sec:ipc_named_pipe}), o quando + \textit{fifo}, vedi sez.~\ref{sec:ipc_named_pipe}), o quando si vuole aprire un file di dispositivo per eseguire una \func{ioctl} (vedi sez.~\ref{sec:file_fcntl_ioctl}).\\ @@ -1327,7 +1327,7 @@ standard che si vuole redirigere e poi aprire direttamente con \func{open} il file vi si vuole far corrispondere, invece di duplicare un file descriptor che si è già aperto. La risposta sta nel fatto che il file che si vuole redirigere non è detto sia un file regolare, ma potrebbe essere, come accennato, anche -una fifo o un socket, oppure potrebbe essere un file associato ad un file +una \textit{fifo} o un socket, oppure potrebbe essere un file associato ad un file descriptor che si è ereditato già aperto (ad esempio attraverso un'altra \func{exec}) da un processo antenato del padre, del quale non si conosce il nome. Operando direttamente con i file descriptor \func{dup} consente di @@ -2629,7 +2629,7 @@ esso viene preventivamente chiuso e tutti i dati pendenti vengono scaricati. Infine \func{fdopen} viene usata per associare uno \textit{stream} ad un file descriptor esistente ottenuto tramite una altra funzione (ad esempio con una \func{open}, una \func{dup}, o una \func{pipe}) e serve quando si vogliono -usare gli \textit{stream} con file come le fifo o i socket, che non possono +usare gli \textit{stream} con file come le \textit{fifo} o i socket, che non possono essere aperti con le funzioni delle librerie standard del C. \begin{table}[htb] @@ -2870,9 +2870,9 @@ all'interno di un file per effettuare operazioni di lettura o scrittura in un punto prestabilito, sempre che l'operazione di riposizionamento sia supportata dal file sottostante lo \textit{stream}, nel caso cioè in cui si ha a che fare con quello che viene detto un file ad \textsl{accesso casuale}. Dato che in un -sistema Unix esistono vari tipi di file, come le fifo ed i file di dispositivo -(ad esempio i terminali), non è scontato che questo sia vero in generale, pur -essendolo sempre nel caso di file di dati. +sistema Unix esistono vari tipi di file, come le \textit{fifo} ed i file di +dispositivo (ad esempio i terminali), non è scontato che questo sia vero in +generale, pur essendolo sempre nel caso di file di dati. Con Linux ed in generale in ogni sistema unix-like la posizione nel file, come abbiamo già visto in sez.~\ref{sec:file_lseek}, è espressa da un intero diff --git a/intro.tex b/intro.tex index fc9c791..1f04743 100644 --- a/intro.tex +++ b/intro.tex @@ -405,8 +405,8 @@ il concetto dell'\textit{everything is a file}, deve fornire una interfaccia che consenta di operare sui file, sia che questi corrispondano ai normali file di dati, o ai cosiddetti ``\textsl{file speciali}'', come i file di dispositivo (o \textit{device file}) che permettono di accedere alle -periferiche o le fifo ed i socket che forniscono funzionalità di comunicazione -fra processi (torneremo su questo in sez.~\ref{sec:file_mknod}). +periferiche o le \textit{fifo} ed i socket che forniscono funzionalità di +comunicazione fra processi (torneremo su questo in sez.~\ref{sec:file_mknod}). Il secondo aspetto è che per poter utilizzare dei normali file di dati il kernel deve provvedere ad organizzare e rendere accessibile in maniera @@ -516,8 +516,8 @@ filesystem, compresa un'altra directory, si ottiene naturalmente un'organizzazione ad albero inserendo nomi di directory dentro altre directory. All'interno dello stesso albero si potranno poi inserire anche tutti gli altri oggetti previsti l'interfaccia del VFS (su cui torneremo in -sez.~\ref{sec:file_file_types}), come le fifo, i collegamenti simbolici, i -socket e gli stessi file di dispositivo. +sez.~\ref{sec:file_file_types}), come le \textit{fifo}, i collegamenti +simbolici, i socket e gli stessi file di dispositivo. La convenzione usata nei sistemi unix-like per indicare i \textit{pathname} dei file è quella di usare il carattere ``\texttt{/}'' come separatore fra i diff --git a/ipc.tex b/ipc.tex index e777487..3acb751 100644 --- a/ipc.tex +++ b/ipc.tex @@ -648,7 +648,7 @@ due volte, prima in lettura e poi in scrittura, per evitare di dover gestire all'interno del ciclo principale il caso in cui il server è in ascolto ma non ci sono client che effettuano richieste. Si ricordi infatti che quando una \textit{fifo} è aperta solo dal capo in lettura, l'esecuzione di \func{read} -ritorna con zero byte (si ha cioè una condizione di end-of-file). +ritorna con zero byte (si ha cioè una condizione di \textit{end-of-file}). Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque client non apre a sua volta la \textit{fifo} nota in scrittura per effettuare diff --git a/tcpsock.tex b/tcpsock.tex index d74edee..d6b5a94 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -2468,12 +2468,13 @@ utilizzando un analizzatore di traffico come \cmd{tcpdump}. Il comando permette di selezionare, nel traffico di rete generato su una macchina, i pacchetti che interessano, stampando a video (o salvando su disco) il loro contenuto. Non staremo qui ad entrare nei dettagli dell'uso del programma, che -sono spiegati dalla pagina di manuale; per l'uso che vogliamo farne quello che -ci interessa è, posizionandosi sulla macchina che fa da client, selezionare -tutti i pacchetti che sono diretti o provengono dalla macchina che fa da -server. In questo modo (posto che non ci siano altre connessioni col server, -cosa che avremo cura di evitare) tutti i pacchetti rilevati apparterranno alla -nostra sessione di interrogazione del servizio. +sono spiegati dalla pagina di manuale;\footnote{per una trattazione di base si + può consultare sez.~5.2.2 di \cite{SGL}.} per l'uso che vogliamo farne +quello che ci interessa è, posizionandosi sulla macchina che fa da client, +selezionare tutti i pacchetti che sono diretti o provengono dalla macchina che +fa da server. In questo modo (posto che non ci siano altre connessioni col +server, cosa che avremo cura di evitare) tutti i pacchetti rilevati +apparterranno alla nostra sessione di interrogazione del servizio. Il comando \cmd{tcpdump} permette selezioni molto complesse, basate sulle interfacce su cui passano i pacchetti, sugli indirizzi IP, sulle porte, sulle @@ -2514,6 +2515,7 @@ Si noti come a partire dal secondo pacchetto sia sempre attivo il campo quest'ultimo, a partire dal terzo pacchetto, viene espresso in forma relativa per maggiore compattezza. Il campo \texttt{win} in ogni riga indica la \textit{advertised window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. + Allora si può verificare dall'output del comando come venga appunto realizzata la sequenza di pacchetti descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un primo pacchetto con il SYN che inizia la connessione, a @@ -2527,9 +2529,10 @@ una prima riga sul client; al momento in cui facciamo questo si genera una sequenza di altri quattro pacchetti. Il primo, dal client al server, contraddistinto da una lettera \texttt{P} che significa che il flag PSH è impostato, contiene la nostra riga (che è appunto di 11 caratteri), e ad esso -il server risponde immediatamente con un pacchetto vuoto di ricevuto. Poi -tocca al server riscrivere indietro quanto gli è stato inviato, per cui sarà -lui a mandare indietro un terzo pacchetto con lo stesso contenuto appena +il server risponde immediatamente con un pacchetto vuoto di ricevuto. + +Poi tocca al server riscrivere indietro quanto gli è stato inviato, per cui +sarà lui a mandare indietro un terzo pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel client che lo stamperà a video. @@ -2617,7 +2620,7 @@ di errore, per questo dovremo riscrivere la funzione \func{ClientEcho}, in modo da controllare gli stati di uscita delle varie chiamate. Si è riportata la nuova versione della funzione in fig.~\ref{fig:TCP_ClientEcho_second}. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/ClientEcho_second.c} @@ -2664,19 +2667,20 @@ sez.~\ref{sec:TCP_sock_multiplexing}. \label{sec:TCP_conn_crash} La terminazione del server è solo uno dei possibili scenari di terminazione -della connessione, un altro caso è ad esempio quello in cui si ha un crollo -della rete, cosa che potremo simulare facilmente staccando il cavo di rete. -Un'altra condizione è quella di un blocco della macchina completo della su cui -gira il server che deve essere riavviata, cosa che potremo simulare eseguendo -un reset fisico,\footnote{un normale shutdown non va bene; in tal caso infatti - il sistema provvede a terminare tutti i processi, per cui la situazione - sarebbe sostanzialmente identica alla precedente.} che, in maniera più -gentile, riavviando la macchina dopo aver interrotto la connessione di rete. - -Cominciamo ad analizzare il primo caso, il crollo della rete. Ripetiamo la -nostra sessione di lavoro precedente, lanciamo il client, scriviamo una prima -riga, poi stacchiamo il cavo e scriviamo una seconda riga. Il risultato che -otterremo è: +della connessione, un altro caso è ad esempio quello in cui si ha +un'interruzione sulla rete, cosa che potremo simulare facilmente staccando il +cavo di rete. Un'altra condizione è quella di un blocco completo della +macchina su cui gira il server che deve essere riavviata, cosa che potremo +simulare sia eseguendo un reset fisico (un normale shutdown non va bene; in +tal caso infatti il sistema provvede a terminare tutti i processi, per cui la +situazione sarebbe sostanzialmente identica alla precedente) oppure, in +maniera più gentile, riavviando la macchina dopo aver interrotto la +connessione di rete. + +Cominciamo ad analizzare il primo caso, l'interruzione del collegamento di +rete. Ripetiamo la nostra sessione di lavoro precedente, lanciamo il client, +scriviamo una prima riga, poi stacchiamo il cavo e scriviamo una seconda +riga. Il risultato che otterremo è: \begin{Console} [piccardi@gont sources]$ \textbf{./echo 192.168.1.141} Prima riga @@ -2771,7 +2775,7 @@ quando la macchina è su una rete remota, è \errcode{ENETUNREACH}; esso viene riportato alla ricezione di un pacchetto ICMP di \textit{destination unreachable} da parte del router che individua l'interruzione della connessione. Di nuovo anche qui il risultato finale dipende da quale è il -meccanismo più veloce ad accorgersi del problema. +meccanismo più veloce che porta ad accorgersi del problema. Se però agiamo sui parametri del kernel, e scriviamo in \file{tcp\_retries2} un valore di tentativi più basso, possiamo evitare la scadenza della @@ -2860,15 +2864,15 @@ sez.~\ref{sec:sock_generic_options}) che provvede all'esecuzione di questo controllo. -\section{L'uso dell'I/O multiplexing} +\section{L'uso dell'\textit{I/O multiplexing}} \label{sec:TCP_sock_multiplexing} -Affronteremo in questa sezione l'utilizzo dell'I/O multiplexing, affrontato in -sez.~\ref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già -in sez.~\ref{sec:TCP_server_crash} era emerso il problema relativo al client -del servizio echo che non era in grado di accorgersi della terminazione -precoce del server, essendo bloccato nella lettura dei dati immessi da -tastiera. +Affronteremo in questa sezione l'utilizzo dell'\textit{I/O multiplexing}, +affrontato in sez.~\ref{sec:file_multiplexing}, nell'ambito delle applicazioni +di rete. Già in sez.~\ref{sec:TCP_server_crash} era emerso il problema +relativo al client del servizio \textit{echo} che non era in grado di +accorgersi della terminazione precoce del server, essendo bloccato nella +lettura dei dati immessi da tastiera. Abbiamo visto in sez.~\ref{sec:file_multiplexing} quali sono le funzionalità del sistema che ci permettono di tenere sotto controllo più file descriptor in @@ -2882,9 +2886,9 @@ asincrona, per cui riprenderemo l'argomento in questa sezione. \subsection{Il comportamento della funzione \func{select} con i socket.} \label{sec:TCP_sock_select} -Iniziamo con la prima delle funzioni usate per l'I/O multiplexing, +Iniziamo con la prima delle funzioni usate per l'\textit{I/O multiplexing}, \func{select}; il suo funzionamento è già stato descritto in dettaglio in -sez.~\ref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì; +sez.~\ref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì; sappiamo che la funzione ritorna quando uno o più dei file descriptor messi sotto controllo è pronto per la relativa operazione. @@ -2914,10 +2918,10 @@ pronto per la lettura sono le seguenti: sez.~\ref{sec:TCP_conn_term}) sulla connessione. In questo caso una operazione di lettura avrà successo, ma non risulteranno presenti dati (in sostanza \func{read} ritornerà con un valore nullo) per indicare la - condizione di end-of-file. + condizione di \textit{end-of-file}. \item c'è stato un errore sul socket. In questo caso una operazione di lettura non si bloccherà ma restituirà una condizione di errore (ad esempio - \func{read} restituirà -1) e imposterà la variabile \var{errno} al relativo + \func{read} restituirà $-1$) e imposterà la variabile \var{errno} al relativo valore. Vedremo in sez.~\ref{sec:sock_generic_options} come sia possibile estrarre e cancellare gli errori pendenti su un socket senza usare \func{read} usando l'opzione \const{SO\_ERROR}. @@ -2939,7 +2943,7 @@ pronto per la scrittura sono le seguenti: valore della \textsl{soglia di basso livello} in scrittura ed inoltre o il socket è già connesso o non necessita (ad esempio è UDP) di connessione. Il valore della soglia è espresso in numero di byte e può essere impostato con - l'opzione del socket \const{SO\_SNDLOWAT} (trattata in + l'opzione del socket \const{SO\_SNDLOWAT} (trattata in sez.~\ref{sec:sock_generic_options}); il suo valore di default è 2048 per i socket TCP e UDP. In questo caso una operazione di scrittura non si bloccherà e restituirà un valore positivo pari al numero di byte accettati @@ -2983,11 +2987,11 @@ quando c'è la certezza di avere dati a sufficienza.\footnote{questo tipo di -\subsection{Un esempio di I/O multiplexing} +\subsection{Un esempio di \textit{I/O multiplexing}} \label{sec:TCP_multiplex_example} -Abbiamo incontrato la problematica tipica che conduce all'uso dell'I/O -multiplexing nella nostra analisi degli errori in +Abbiamo incontrato la problematica tipica che conduce all'uso dell'\textit{I/O + multiplexing} nella nostra analisi degli errori in sez.~\ref{sec:TCP_conn_early_abort}, quando il nostro client non era in grado di rendersi conto di errori sulla connessione essendo impegnato nella attesa di dati in ingresso dallo \textit{standard input}. @@ -2996,7 +3000,7 @@ In questo caso il problema è quello di dover tenere sotto controllo due diversi file descriptor, lo \textit{standard input}, da cui viene letto il testo che vogliamo inviare al server, e il socket connesso con il server su cui detto testo sarà scritto e dal quale poi si vorrà ricevere la -risposta. L'uso dell'I/O multiplexing consente di tenere sotto controllo +risposta. L'uso dell'\textit{I/O multiplexing} consente di tenere sotto controllo entrambi, senza restare bloccati. Nel nostro caso quello che ci interessa è non essere bloccati in lettura sullo @@ -3010,7 +3014,7 @@ condizione di errore (con un segmento RST) il socket connesso sarà pronto in lettura (nell'ultimo caso anche in scrittura, ma questo non è necessario ai nostri scopi). -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/ClientEcho_third.c} @@ -3044,15 +3048,15 @@ viene ripetuto indefinitamente. Per ogni ciclo si reinizializza per il file descriptor associato al socket \var{socket} e per lo \textit{standard input} (il cui valore si recupera con la funzione \func{fileno}). Questo è necessario in quanto la successiva (\texttt{\small - 13}) chiamata a \func{select} comporta una modifica dei due bit relativi, -che quindi devono essere reimpostati all'inizio di ogni ciclo. + 13}) chiamata a \func{select} comporta una modifica dei due bit relativia +questi file, che quindi devono essere reimpostati all'inizio di ogni ciclo. Si noti come la chiamata a \func{select} venga eseguita usando come primo argomento il valore di \var{maxfd}, precedentemente calcolato, e passando poi il solo \textit{file descriptor set} per il controllo dell'attività in -lettura, negli altri argomenti sono passati tutti puntatori nulli, non -interessando né il controllo delle altre attività, né l'impostazione di un -valore di timeout. +lettura, negli altri argomenti vengono passati tutti puntatori nulli, non +interessando in questo caso né il controllo delle altre attività, né +l'impostazione di un valore di timeout. Al ritorno di \func{select} si provvede a controllare quale dei due file descriptor presenta attività in lettura, cominciando (\texttt{\small 14--24}) @@ -3068,24 +3072,25 @@ sul socket, prevedendo una uscita immediata in caso di errore di scrittura. Controllato lo \textit{standard input} si passa a controllare (\texttt{\small 25--40}) il socket connesso, in caso di attività (\texttt{\small 26}) si esegue subito una \func{read} di cui si controlla il valore di ritorno; se -questo è negativo (\texttt{\small 27--30}) si è avuto un errore e pertanto si -esce immediatamente segnalandolo, se è nullo (\texttt{\small 31--34}) -significa che il server ha chiuso la connessione, e di nuovo si esce con -stampando prima un messaggio di avviso, altrimenti (\texttt{\small 35--39}) si +questo è negativo si è avuto un errore e pertanto si esce immediatamente +segnalandolo (\texttt{\small 27--30}), se è nullo significa che il server ha +chiuso la connessione, e di nuovo si esce con stampando prima un messaggio di +avviso (\texttt{\small 31--34}), altrimenti (\texttt{\small 35--39}) si effettua la terminazione della stringa e la si stampa a sullo \textit{standard - output} (uscendo in caso di errore), per ripetere il ciclo da capo. + output}, uscendo in caso di errore, per ripetere il ciclo da capo. Con questo meccanismo il programma invece di essere bloccato in lettura sullo \textit{standard input} resta bloccato sulla \func{select}, che ritorna soltanto quando viene rilevata attività su uno dei due file descriptor posti sotto controllo. Questo di norma avviene solo quando si è scritto qualcosa sullo \textit{standard input}, o quando si riceve dal socket la risposta a quanto si -era appena scritto. Ma adesso il client diventa capace di accorgersi -immediatamente della terminazione del server; in tal caso infatti il server -chiuderà il socket connesso, ed alla ricezione del FIN la funzione -\func{select} ritornerà (come illustrato in sez.~\ref{sec:TCP_sock_select}) -segnalando una condizione di end of file, per cui il nostro client potrà -uscire immediatamente. +era appena scritto. + +Ma adesso il client diventa capace di accorgersi immediatamente della +terminazione del server; in tal caso infatti il server chiuderà il socket +connesso, ed alla ricezione del FIN la funzione \func{select} ritornerà (come +illustrato in sez.~\ref{sec:TCP_sock_select}) segnalando una condizione di end +of file, per cui il nostro client potrà uscire immediatamente. Riprendiamo la situazione affrontata in sez.~\ref{sec:TCP_server_crash}, terminando il server durante una connessione, in questo caso quello che @@ -3113,13 +3118,14 @@ La differenza è che stavolta potremo scrivere più righe dopo l'interruzione, in quanto il nostro client dopo aver inviato i dati non si bloccherà più nella lettura dal socket, ma nella \func{select}; per questo potrà accettare ulteriore dati che scriverà di nuovo sul socket, fintanto che c'è spazio sul -buffer di uscita (ecceduto il quale si bloccherà in scrittura). Si ricordi -infatti che il client non ha modo di determinare se la connessione è attiva o -meno (dato che in molte situazioni reali l'inattività può essere temporanea). -Tra l'altro se si ricollega la rete prima della scadenza del timeout, potremo -anche verificare come tutto quello che si era scritto viene poi effettivamente -trasmesso non appena la connessione ridiventa attiva, per cui otterremo -qualcosa del tipo: +buffer di uscita (ecceduto il quale si bloccherà in scrittura). + +Si ricordi infatti che il client non ha modo di determinare se la connessione +è attiva o meno (dato che in molte situazioni reali l'inattività può essere +temporanea). Tra l'altro se si ricollega la rete prima della scadenza del +timeout, potremo anche verificare come tutto quello che si era scritto viene +poi effettivamente trasmesso non appena la connessione ridiventa attiva, per +cui otterremo qualcosa del tipo: \begin{Console} [piccardi@gont sources]$ \textbf{./echo 192.168.1.1} Prima riga @@ -3140,56 +3146,61 @@ nel caso di un crollo completo della macchina su cui sta il server. In questo caso di nuovo il client non è in grado di accorgersi di niente dato che si suppone che il programma server non venga terminato correttamente, ma si blocchi tutto senza la possibilità di avere l'emissione di un segmento FIN che -segnala la terminazione della connessione. Di nuovo fintanto che la -connessione non si riattiva (con il riavvio della macchina del server) il -client non è in grado di fare altro che accettare dell'input e tentare di -inviarlo. La differenza in questo caso è che non appena la connessione -ridiventa attiva i dati verranno sì trasmessi, ma essendo state perse tutte le -informazioni relative alle precedenti connessioni ai tentativi di scrittura -del client sarà risposto con un segmento RST che provocherà il ritorno di -\func{select} per la ricezione di un errore di \errcode{ECONNRESET}. +segnala la terminazione della connessione. + +Di nuovo fintanto che la connessione non si riattiva (con il riavvio della +macchina del server) il client non è in grado di fare altro che accettare +dell'input e tentare di inviarlo. La differenza in questo caso è che non +appena la connessione ridiventa attiva i dati verranno sì trasmessi, ma +essendo state perse tutte le informazioni relative alle precedenti connessioni +ai tentativi di scrittura del client sarà risposto con un segmento RST che +provocherà il ritorno di \func{select} per la ricezione di un errore di +\errcode{ECONNRESET}. \subsection{La funzione \func{shutdown}} \label{sec:TCP_shutdown} -Come spiegato in sez.~\ref{sec:TCP_conn_term} il procedimento di chiusura di un -socket TCP prevede che da entrambe le parti venga emesso un segmento FIN. È +Come spiegato in sez.~\ref{sec:TCP_conn_term} il procedimento di chiusura di +un socket TCP prevede che da entrambe le parti venga emesso un segmento FIN. È pertanto del tutto normale dal punto di vista del protocollo che uno dei due -capi chiuda la connessione, quando l'altro capo la lascia -aperta.\footnote{abbiamo incontrato questa situazione nei vari scenari critici - di sez.~\ref{sec:TCP_echo_critical}.} +capi chiuda la connessione quando l'altro capo la lascia aperta; abbiamo +incontrato questa situazione nei vari scenari critici di +sez.~\ref{sec:TCP_echo_critical}. \itindbeg{half-close} -È pertanto possibile avere una situazione in cui un capo della connessione non -avendo più nulla da scrivere, possa chiudere il socket, segnalando così +È pertanto possibile avere una situazione in cui un capo della connessione, +non avendo più nulla da scrivere, possa chiudere il socket, segnalando così l'avvenuta terminazione della trasmissione (l'altro capo riceverà infatti un \textit{end-of-file} in lettura) mentre dall'altra parte si potrà proseguire la trasmissione dei dati scrivendo sul socket che da quel lato è ancora aperto. Questa è quella situazione in cui si dice che il socket è -``\textit{half closed}''. +\textsl{mezzo chiuso} (``\textit{half closed}''). Il problema che si pone è che se la chiusura del socket è effettuata con la -funzione \func{close}, come spiegato in sez.~\ref{sec:TCP_func_close}, si perde -ogni possibilità di poter rileggere quanto l'altro capo può continuare a -scrivere. Per poter permettere allora di segnalare che si è concluso con la +funzione \func{close}, come spiegato in sez.~\ref{sec:TCP_func_close}, si +perde ogni possibilità di poter leggere quanto l'altro capo può star +continuando a scrivere. Per permettere di segnalare che si è finito con la scrittura, continuando al contempo a leggere quanto può provenire dall'altro -capo del socket si può allora usare la funzione \funcd{shutdown}, il cui -prototipo è: -\begin{prototype}{sys/socket.h} -{int shutdown(int sockfd, int how)} +capo del socket, si può usare la funzione \funcd{shutdown}, il cui prototipo +è: -Chiude un lato della connessione fra due socket. - - \bodydesc{La funzione restituisce zero in caso di successo e -1 per un - errore, nel qual caso \var{errno} assumerà i valori: +\begin{funcproto}{ +\fhead{sys/socket.h} +\fdecl{int shutdown(int sockfd, int how)} +\fdesc{Chiude un lato della connessione fra due socket.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{ENOTSOCK}] il file descriptor non corrisponde a un socket. + \item[\errcode{EBADF}] \param{sockfd} non è un file descriptor valido. + \item[\errcode{EINVAL}] il valore di \param{how} non è valido. \item[\errcode{ENOTCONN}] il socket non è connesso. - \end{errlist} - ed inoltre \errval{EBADF}.} -\end{prototype} + \item[\errcode{ENOTSOCK}] il file descriptor non corrisponde a un socket. + \end{errlist}} +\end{funcproto} La funzione prende come primo argomento il socket \param{sockfd} su cui si vuole operare e come secondo argomento un valore intero \param{how} che indica @@ -3218,10 +3229,12 @@ Ci si può chiedere quale sia l'utilità di avere introdotto \const{SHUT\_RDWR} quando questa sembra rendere \func{shutdown} del tutto equivalente ad una \func{close}. In realtà non è così, esiste infatti un'altra differenza con \func{close}, più sottile. Finora infatti non ci siamo presi la briga di -sottolineare in maniera esplicita che, come per i file e le fifo, anche per i -socket possono esserci più riferimenti contemporanei ad uno stesso socket. Per -cui si avrebbe potuto avere l'impressione che sia una corrispondenza univoca -fra un socket ed il file descriptor con cui vi si accede. Questo non è +sottolineare in maniera esplicita che, come per i file e le \textit{fifo}, +anche per i socket possono esserci più riferimenti contemporanei ad uno stesso +socket. + +Per cui si avrebbe potuto avere l'impressione che sia una corrispondenza +univoca fra un socket ed il file descriptor con cui vi si accede. Questo non è assolutamente vero, (e lo abbiamo già visto nel codice del server di fig.~\ref{fig:TCP_echo_server_first_code}), ed è invece assolutamente normale che, come per gli altri oggetti, ci possano essere più file descriptor che @@ -3233,7 +3246,9 @@ soltanto quando il numero di riferimenti a quest'ultimo diventerà nullo. Fintanto che ci sono file descriptor che fanno riferimento ad un socket l'uso di \func{close} si limiterà a deallocare nel processo corrente il file descriptor utilizzato, ma il socket resterà pienamente accessibile attraverso -tutti gli altri riferimenti. Se torniamo all'esempio originale del server di +tutti gli altri riferimenti. + +Se torniamo all'esempio originale del server di fig.~\ref{fig:TCP_echo_server_first_code} abbiamo infatti che ci sono due \func{close}, una sul socket connesso nel padre, ed una sul socket in ascolto nel figlio, ma queste non effettuano nessuna chiusura reale di detti socket, @@ -3251,9 +3266,10 @@ Il caso più comune di uso di \func{shutdown} è comunque quello della chiusura del lato in scrittura, per segnalare all'altro capo della connessione che si è concluso l'invio dei dati, restando comunque in grado di ricevere quanto questi potrà ancora inviarci. Questo è ad esempio l'uso che ci serve per -rendere finalmente completo il nostro esempio sul servizio \textit{echo}. Il -nostro client infatti presenta ancora un problema, che nell'uso che finora ne -abbiamo fatto non è emerso, ma che ci aspetta dietro l'angolo non appena +rendere finalmente completo il nostro esempio sul servizio \textit{echo}. + +Il nostro client infatti presenta ancora un problema, che nell'uso che finora +ne abbiamo fatto non è emerso, ma che ci aspetta dietro l'angolo non appena usciamo dall'uso interattivo e proviamo ad eseguirlo redirigendo \textit{standard input} e \textit{standard output}. Così se eseguiamo: \begin{Console} @@ -3267,7 +3283,7 @@ comunicazione via rete; quando redirigiamo lo \textit{standard input} il nostro client inizierà a leggere il contenuto del file \texttt{../fileadv.tex} a blocchi di dimensione massima pari a \texttt{MAXLINE} per poi scriverlo, alla massima velocità consentitagli dalla rete, sul socket. Dato che la -connessione è con una macchina remota occorre un certo tempo perché i +connessione è con una macchina remota, occorre un certo tempo perché i pacchetti vi arrivino, vengano processati, e poi tornino indietro. Considerando trascurabile il tempo di processo, questo tempo è quello impiegato nella trasmissione via rete, che viene detto RTT (dalla @@ -3277,15 +3293,15 @@ denominazione inglese \itindex{Round~Trip~Time~(RTT)} \textit{Round Trip A questo punto, se torniamo al codice mostrato in fig.~\ref{fig:TCP_ClientEcho_third}, possiamo vedere che mentre i pacchetti sono in transito sulla rete il client continua a leggere e a scrivere fintanto -che il file in ingresso finisce. Però non appena viene ricevuto un end-of-file -in ingresso il nostro client termina. Nel caso interattivo, in cui si -inviavano brevi stringhe una alla volta, c'era sempre il tempo di eseguire la -lettura completa di quanto il server rimandava indietro. In questo caso -invece, quando il client termina, essendo la comunicazione saturata e a piena -velocità, ci saranno ancora pacchetti in transito sulla rete che devono -arrivare al server e poi tornare indietro, ma siccome il client esce -immediatamente dopo la fine del file in ingresso, questi non faranno a tempo a -completare il percorso e verranno persi. +che il file in ingresso finisce. Però non appena viene ricevuto un +\textit{end-of-file} in ingresso il nostro client termina. Nel caso +interattivo, in cui si inviavano brevi stringhe una alla volta, c'era sempre +il tempo di eseguire la lettura completa di quanto il server rimandava +indietro. In questo caso invece, quando il client termina, essendo la +comunicazione saturata e a piena velocità, ci saranno ancora pacchetti in +transito sulla rete che devono arrivare al server e poi tornare indietro, ma +siccome il client esce immediatamente dopo la fine del file in ingresso, +questi non faranno a tempo a completare il percorso e verranno persi. Per evitare questo tipo di problema, invece di uscire una volta completata la lettura del file in ingresso, occorre usare \func{shutdown} per effettuare la @@ -3323,7 +3339,7 @@ nullo, che serve a mantenere traccia dell'avvenuta conclusione della lettura del file in ingresso. La seconda modifica (\texttt{\small 12--15}) è stata quella di rendere -subordinato ad un valore nullo di \var{eof} l'impostazione del file descriptor +subordinata ad un valore nullo di \var{eof} l'impostazione del file descriptor set per l'osservazione dello \textit{standard input}. Se infatti il valore di \var{eof} è non nullo significa che si è già raggiunta la fine del file in ingresso ed è pertanto inutile continuare a tenere sotto controllo lo @@ -3344,30 +3360,31 @@ In questo modo anche se la lettura del file in ingresso è conclusa, la funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua ad eseguirlo ripetendo la chiamata a \func{select} per tenere sotto controllo soltanto il socket connesso, dal quale possono arrivare altri dati, che -saranno letti (\texttt{\small 31}), ed opportunamente trascritti +saranno letti (\texttt{\small 31}) ed opportunamente trascritti (\texttt{\small 44--48}) sullo \textit{standard output}. Il ritorno della funzione, e la conseguente terminazione normale del client, viene invece adesso gestito all'interno (\texttt{\small 30--49}) della lettura dei dati dal socket; se infatti dalla lettura del socket si riceve una -condizione di end-of-file, la si tratterà (\texttt{\small 36--43}) in maniera -diversa a seconda del valore di \var{eof}. Se infatti questa è diversa da zero -(\texttt{\small 37--39}), essendo stata completata la lettura del file in -ingresso, vorrà dire che anche il server ha concluso la trasmissione dei dati -restanti, e si potrà uscire senza errori, altrimenti si stamperà +condizione di \textit{end-of-file}, la si tratterà (\texttt{\small 36--43}) in +maniera diversa a seconda del valore di \var{eof}. Se infatti questa è diversa +da zero (\texttt{\small 37--39}), essendo stata completata la lettura del file +in ingresso, vorrà dire che anche il server ha concluso la trasmissione dei +dati restanti, e si potrà uscire senza errori, altrimenti si stamperà (\texttt{\small 40--42}) un messaggio di errore per la chiusura precoce della connessione. -\subsection{Un server basato sull'I/O multiplexing} +\subsection{Un server basato sull'\textit{I/O multiplexing}} \label{sec:TCP_serv_select} Seguendo di nuovo le orme di Stevens in \cite{UNP1} vediamo ora come con -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 realizzazione diversa rispetto a - quella presentata da Stevens in \cite{UNP1}.} +l'utilizzo dell'\textit{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 + 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 @@ -3378,7 +3395,7 @@ file descriptor attivi, operando direttamente su ciascuno di essi. \begin{figure}[!htb] \centering \includegraphics[width=13cm]{img/TCPechoMult} - \caption{Schema del nuovo server echo basato sull'I/O multiplexing.} + \caption{Schema del nuovo server echo basato sull'\textit{I/O multiplexing}.} \label{fig:TCP_echo_multiplex} \end{figure} @@ -3405,7 +3422,7 @@ disponibile coi sorgenti allegati nel file \texttt{select\_echod.c}. 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 realizzare -lo schema mostrato in fig.~\ref{fig:TCP_echo_multiplex}, il programma usa una +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. @@ -3414,19 +3431,19 @@ Prima di entrare nel ciclo principale (\texttt{\small 6--56}) la nostra tabella viene inizializzata (\texttt{\small 2}) a zero (valore che utilizzeremo come indicazione del fatto che il relativo file descriptor non è aperto), mentre il valore massimo (\texttt{\small 3}) per i file descriptor -aperti viene impostato a quello del socket in ascolto,\footnote{in quanto esso - è l'unico file aperto, oltre i tre standard, e pertanto avrà il valore più - alto.} che verrà anche (\texttt{\small 4}) inserito nella tabella. +aperti viene impostato a quello del socket in ascolto, in quanto esso è +l'unico file aperto, oltre i tre standard, e pertanto avrà il valore più alto, +che verrà anche (\texttt{\small 4}) inserito nella tabella. La prima sezione (\texttt{\small 7--10}) del ciclo principale esegue la costruzione del \textit{file descriptor set} \var{fset} in base ai socket -connessi in un certo momento; all'inizio ci sarà soltanto il socket in -ascolto, ma nel prosieguo delle operazioni, verranno utilizzati anche tutti i -socket connessi registrati nella tabella \var{fd\_open}. Dato che la chiamata -di \func{select} modifica il valore del \textit{file descriptor set}, è -necessario ripetere (\texttt{\small 7}) ogni volta il suo azzeramento, per poi -procedere con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket -trovati attivi. +connessi in un certo momento; all'inizio ci sarà soltanto il socket in ascolto +ma nel prosieguo delle operazioni verranno utilizzati anche tutti i socket +connessi registrati nella tabella \var{fd\_open}. Dato che la chiamata di +\func{select} modifica il valore del \textit{file descriptor set} è necessario +ripetere (\texttt{\small 7}) ogni volta il suo azzeramento per poi procedere +con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket trovati +attivi. Per far questo si usa la caratteristica dei file descriptor, descritta in sez.~\ref{sec:file_open_close}, per cui il kernel associa sempre ad ogni nuovo @@ -3436,10 +3453,10 @@ che sarà sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, fino al valore massimo di \var{max\_fd} che dovremo aver cura di tenere aggiornato. Dopo di che basterà controllare (\texttt{\small 9}) nella nostra tabella se il file descriptor è in uso o meno,\footnote{si tenga presente che - benché il kernel assegni sempre il primo valore libero, dato che nelle - operazioni i socket saranno aperti e chiusi in corrispondenza della - creazione e conclusione delle connessioni, si potranno sempre avere dei - \textsl{buchi} nella nostra tabella.} e impostare \var{fset} di conseguenza. + benché il kernel assegni sempre il primo valore libero, si potranno sempre + avere dei \textsl{buchi} nella nostra tabella dato che nelle operazioni i + socket saranno aperti e chiusi in corrispondenza della creazione e + conclusione delle connessioni.} e impostare \var{fset} di conseguenza. Una volta inizializzato con i socket aperti il nostro \textit{file descriptor set} potremo chiamare \func{select} per fargli osservare lo stato degli @@ -3454,14 +3471,14 @@ uscire stampando un messaggio di errore. Se invece la funzione ritorna normalmente avremo in \var{n} il numero di socket da controllare. Nello specifico si danno due possibili casi diversi per cui \func{select} può essere ritornata: o si è ricevuta una nuova connessione -ed è pronto il socket in ascolto, sul quale si può eseguire \func{accept} o +ed è pronto il socket in ascolto, sul quale si può eseguire \func{accept}, o c'è attività su uno dei socket connessi, sui quali si può eseguire \func{read}. Il primo caso viene trattato immediatamente (\texttt{\small 17--26}): si controlla (\texttt{\small 17}) che il socket in ascolto sia fra quelli attivi, nel qual caso anzitutto (\texttt{\small 18}) se ne decrementa il numero in -\var{n}; poi, inizializzata (\texttt{\small 19}) la lunghezza della struttura +\var{n}. Poi, inizializzata (\texttt{\small 19}) la lunghezza della struttura degli indirizzi, si esegue \func{accept} per ottenere il nuovo socket connesso controllando che non ci siano errori (\texttt{\small 20--23}). In questo caso non c'è più la necessità di controllare per interruzioni dovute a segnali, in @@ -3471,18 +3488,20 @@ file descriptor alla tabella di quelli connessi, ed inoltre, se è il caso, aggiornare (\texttt{\small 25}) il valore massimo in \var{max\_fd}. Una volta controllato l'arrivo di nuove connessioni si passa a verificare se -vi sono dati sui socket connessi, per questo si ripete un ciclo +ci sono dati sui socket connessi, per questo si ripete un ciclo (\texttt{\small 29--55}) fintanto che il numero di socket attivi \var{n} resta diverso da zero; in questo modo se l'unico socket con attività era quello connesso, avendo opportunamente decrementato il contatore, il ciclo verrà -saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del -\textit{file descriptor set} con i nuovi valori nella tabella) alla chiamata -di \func{accept}. Se il socket attivo non è quello in ascolto, o ce ne sono -comunque anche altri, il valore di \var{n} non sarà nullo ed il controllo sarà +saltato e si ritornerà immediatamente, ripetuta l'inizializzazione del +\textit{file descriptor set} con i nuovi valori nella tabella, alla chiamata +di \func{accept}. + +Se il socket attivo non è quello in ascolto, o ce ne sono comunque anche +altri, il valore di \var{n} non sarà nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque si inizializza (\texttt{\small - 28}) il valore della variabile \var{i} che useremo come indice nella tabella -\var{fd\_open} al valore minimo, corrispondente al file descriptor del socket -in ascolto. + 28}) il valore della variabile \var{i}, che useremo come indice nella +tabella, \var{fd\_open} al valore minimo, corrispondente al file descriptor +del socket in ascolto. Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore dell'indice \var{i} per posizionarsi sul primo valore possibile per un file @@ -3494,15 +3513,15 @@ attivi, e nel caso si esegue (\texttt{\small 33}) una lettura, uscendo con un messaggio in caso di errore (\texttt{\small 34--38}). Se (\texttt{\small 39}) il numero di byte letti \var{nread} è nullo si è in -presenza del caso di un \textit{end-of-file}, indice che una connessione che -si è chiusa, che deve essere trattato (\texttt{\small 39--48}) opportunamente. -Il primo passo è chiudere (\texttt{\small 40}) anche il proprio capo del -socket e rimuovere (\texttt{\small 41}) il file descriptor dalla tabella di -quelli aperti, inoltre occorre verificare (\texttt{\small 42}) se il file -descriptor chiuso è quello con il valore più alto, nel qual caso occorre -trovare (\texttt{\small 42--46}) il nuovo massimo, altrimenti (\texttt{\small - 47}) si può ripetere il ciclo da capo per esaminare (se ne restano) -ulteriori file descriptor attivi. +presenza di un \textit{end-of-file}, indice che una connessione che si è +chiusa, che deve essere trattato (\texttt{\small 39--48}) opportunamente. Il +primo passo è chiudere (\texttt{\small 40}) anche il proprio capo del socket e +rimuovere (\texttt{\small 41}) il file descriptor dalla tabella di quelli +aperti, inoltre occorre verificare (\texttt{\small 42}) se il file descriptor +chiuso è quello con il valore più alto, nel qual caso occorre trovare +(\texttt{\small 42--46}) il nuovo massimo, altrimenti (\texttt{\small 47}) si +può ripetere il ciclo da capo per esaminare (se ne restano) ulteriori file +descriptor attivi. Se però è stato chiuso il file descriptor più alto, dato che la scansione dei file descriptor attivi viene fatta a partire dal valore più basso, questo @@ -3521,11 +3540,12 @@ che nel ciclo si esegue una sola lettura, contrariamente a quanto fatto con la precedente versione (si riveda il codice di fig.~\ref{fig:TCP_ServEcho_second}) in cui si continuava a leggere fintanto che non si riceveva un \textit{end-of-file}, questo perché usando l'\textit{I/O multiplexing} non si -vuole essere bloccati in lettura. L'uso di \func{select} ci permette di -trattare automaticamente anche il caso in cui la \func{read} non è stata in -grado di leggere tutti i dati presenti sul socket, dato che alla iterazione -successiva \func{select} ritornerà immediatamente segnalando l'ulteriore -disponibilità. +vuole essere bloccati in lettura. + +L'uso di \func{select} ci permette di trattare automaticamente anche il caso +in cui la \func{read} non è stata in grado di leggere tutti i dati presenti +sul socket, dato che alla iterazione successiva \func{select} ritornerà +immediatamente segnalando l'ulteriore disponibilità. Il nostro server comunque soffre di una vulnerabilità per un attacco di tipo \textit{Denial of Service}. Il problema è che in caso di blocco di una @@ -3533,8 +3553,9 @@ qualunque delle funzioni di I/O, non avendo usato processi separati, tutto il server si ferma e non risponde più a nessuna richiesta. Abbiamo scongiurato questa evenienza per l'I/O in ingresso con l'uso di \func{select}, ma non vale altrettanto per l'I/O in uscita. Il problema pertanto può sorgere qualora una -delle chiamate a \func{write} effettuate da \func{FullWrite} si blocchi. Con -il funzionamento normale questo non accade in quanto il server si limita a +delle chiamate a \func{write} effettuate da \func{FullWrite} si blocchi. + +Con il funzionamento normale questo non accade in quanto il server si limita a scrivere quanto riceve in ingresso, ma qualora venga utilizzato un client malevolo che esegua solo scritture e non legga mai indietro l'\textsl{eco} del server, si potrebbe giungere alla saturazione del buffer di scrittura, ed al @@ -3547,22 +3568,21 @@ modalità non bloccante, concludendo le operazioni qualora non vadano a buon fine. - -\subsection{I/O multiplexing con \func{poll}} +\subsection{\textit{I/O multiplexing} con \func{poll}} \label{sec:TCP_serv_poll} -Finora abbiamo trattato le problematiche risolubili con l'I/O multiplexing -impiegando la funzione \func{select}; questo è quello che avviene nella -maggior parte dei casi, in quanto essa è nata sotto BSD proprio per affrontare -queste problematiche con i socket. Abbiamo però visto in +Finora abbiamo trattato le problematiche risolubili con l'\textit{I/O + multiplexing} impiegando la funzione \func{select}. Questo è quello che +avviene nella maggior parte dei casi, in quanto essa è nata sotto BSD proprio +per affrontare queste problematiche con i socket. Abbiamo però visto in sez.~\ref{sec:file_multiplexing} come la funzione \func{poll} possa costituire -una alternativa a \func{select}, con alcuni vantaggi.\footnote{non soffrendo - delle limitazioni dovute all'uso dei \textit{file descriptor set}.} +una alternativa a \func{select}, con alcuni vantaggi, non soffrendo delle +limitazioni dovute all'uso dei \textit{file descriptor set}. Ancora una volta in sez.~\ref{sec:file_poll} abbiamo trattato la funzione in maniera generica, parlando di file descriptor, ma come per \func{select} -quando si ha a che fare con dei socket il concetto di essere \textsl{pronti} -per l'I/O deve essere specificato nei dettagli, per tener conto delle +quando si ha a che fare con dei socket, il concetto di essere \textsl{pronti} +per l'I/O deve essere specificato nei dettagli per tener conto delle condizioni della rete. Inoltre deve essere specificato come viene classificato il traffico nella suddivisione fra dati normali e prioritari. In generale pertanto: @@ -3679,7 +3699,7 @@ altrimenti si provvederà (\texttt{\small 32}) a decrementare il numero \var{n} di file descriptor attivi da controllare e ad eseguire (\texttt{\small 33}) la lettura, ed in caso di errore (\texttt{\small 34--37}) al solito lo si notificherà uscendo immediatamente. Qualora invece si ottenga una condizione -di end-of-file (\texttt{\small 38--47}) si provvederà a chiudere +di \textit{end-of-file} (\texttt{\small 38--47}) si provvederà a chiudere (\texttt{\small 39}) anche il nostro capo del socket e a marcarlo (\texttt{\small 40}) nella struttura ad esso associata come inutilizzato. Infine dovrà essere ricalcolato (\texttt{\small 41--45}) un eventuale nuovo @@ -3689,7 +3709,7 @@ sul socket. Se invece si sono letti dei dati si provvede (\texttt{\small 48}) ad effettuarne la riscrittura all'indietro, con il solito controllo ed eventuale -uscita e notifica in caso si errore (\texttt{\small 49--52}). +uscita e notifica in caso di errore (\texttt{\small 49--52}). Come si può notare la logica del programma è identica a quella vista in fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; @@ -3699,8 +3719,7 @@ dai dati in ingresso. Si applicano comunque anche a questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}. - -\subsection{I/O multiplexing con \textit{epoll}} +\subsection{\textit{I/O multiplexing} con \textit{epoll}} \label{sec:TCP_serv_epoll} Da fare. -- 2.30.2