Riorganizzato il capitolo sui file avanzati, con degli esempi in piu
authorSimone Piccardi <piccardi@gnulinux.it>
Fri, 26 Dec 2003 19:20:04 +0000 (19:20 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Fri, 26 Dec 2003 19:20:04 +0000 (19:20 +0000)
sull'uso di pselect. Inserita (e commentata) anche la seconda versione della
funzione ServEcho utilizzata dal server echo normale.

fileadv.tex
listati/ServEcho_second.c [new file with mode: 0644]
tcpsock.tex
tcpsockadv.tex

index fb516a3179faf40307aa38ef7400eef1db4df549..19f7dabdf8f371337bc8bec1b4f235d2cddc37f4 100644 (file)
 \label{cha:file_advanced}
 
 In questo capitolo affronteremo le tematiche relative alla gestione avanzata
-dei file, che non sono state trattate in \capref{cha:file_unix_interface},
-dove ci si è limitati ad una panoramica delle funzioni base. In particolare
-tratteremo delle funzioni di input/output avanzato e del \textit{file
-  locking}.
+dei file. In particolare tratteremo delle funzioni di input/output avanzato,
+che permettono una gestione più sofisticata dell'I/O su file, a partire da
+quelle che permettono di gestire l'accesso contemporaneo a più file, per
+concludere con la gestione dell'I/O mappato in memoria. Dedicheremo poi la
+fine del capitolo alle problematiche del \textit{file locking}.
 
 
-\section{Le funzioni di I/O avanzato}
-\label{sec:file_advanced_io}
+\section{L'\textit{I/O multiplexing}}
+\label{sec:file_multiplexing}
 
-In questa sezione esamineremo le funzioni che permettono una gestione più
-sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
-l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
-mappato in memoria.
+Uno dei problemi che si presentano quando si deve operare contemporaneamente
+su molti file usando le funzioni illustrate in
+\capref{cha:file_unix_interface} e \capref{cha:files_std_interface} è che si
+può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
+problema. In questa sezione forniremo una introduzione a questa problematica
+ed analizzeremo le varie funzioni usate per implementare questa modalità di
+I/O.
 
 
-\subsection{La modalità di I/O \textsl{non-bloccante}}
+\subsection{La problematica dell'\textit{I/O multiplexing} e l'uso
+  dell'\textsl{I/O non-bloccante}}
 \label{sec:file_noblocking}
 
 Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
@@ -40,45 +46,54 @@ lettura possono bloccarsi quando non ci sono dati disponibili sul descrittore
 su cui si sta operando.
 
 Questo comportamento causa uno dei problemi più comuni che ci si trova ad
-affrontare nelle operazioni di I/O, che è quello che si verifica quando si
-devono eseguire operazioni che possono bloccarsi su più file descriptor:
-mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti
-dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata
-inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
-\textit{deadlock}\index{deadlock}.
+affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
+più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
+possibile prevedere quando questo può avvenire (il caso più classico è quello
+di un server in attesa di dati in ingresso da vari client). Quello che può
+accadere è di restare bloccati nell'eseguire una operazione su un file
+descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere
+un'altro disponibile. Questo comporta nel migliore dei casi una operazione
+ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
+nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
+da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
+potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
 
 Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento aprendo un file in modalità
-\textsl{non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK} nella
-chiamata di \func{open}. In questo caso le funzioni di input/output che
-altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
-l'errore \errcode{EAGAIN}.
+questo tipo di comportamento delle funzioni di I/O aprendo un file in quella
+che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
+\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
+di input/output eseguite sul file che si sarebbero bloccate, ritornano
+immediatamente, restituendo l'errore \errcode{EAGAIN}.
 
 L'utilizzo di questa modalità di I/O permette di risolvere il problema
 controllando a turno i vari file descriptor, in un ciclo in cui si ripete
 l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
 detta \textit{polling}\index{polling}, è estremamente inefficiente: si tiene
 costantemente impiegata la CPU solo per eseguire in continuazione delle system
-call che nella gran parte dei casi falliranno. Per evitare questo, come
-vedremo in \secref{sec:file_multiplexing}, è stata introdotta una nuova
-interfaccia di programmazione, che comporta comunque l'uso della modalità di
-I/O non bloccante.
-
-
-
-\subsection{L'I/O multiplexing}
-\label{sec:file_multiplexing}
-
-Per superare il problema di dover usare il \textit{polling}\index{polling} per
-controllare la possibilità di effettuare operazioni su un gruppo di file
-aperti in modalità non bloccante, sia BSD che System V hanno introdotto delle
-nuove funzioni in grado di sospendere l'esecuzione di un processo fin quando
-l'accesso ad un dato insieme di file diventi possibile.  Il primo ad
-introdurre questa modalità di operazione, chiamata usualmente \textit{I/O
-  multiplexing}, è stato BSD,\footnote{la funzione è apparsa in BSD4.2 e
-  standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che
-  supportano i \textit{socket}\index{socket}, compreso le varianti di System
-  V.}  con la funzione \funcd{select}, il cui prototipo è:
+call che nella gran parte dei casi falliranno. 
+
+Per superare questo problema è stato introdotto il concetto di \textit{I/O
+  multiplexing}, una nuova modalità di operazioni che consenta di tenere sotto
+controllo più file descriptor in contemporanea, permettendo di bloccare un
+processo quando le operazioni volute non sono possibili, e di riprenderne
+l'esecuzione una volta che almeno una di quelle richieste sia disponibile, in
+modo da poterla eseguire con la sicurezza di non restare bloccati.
+
+Dato che, come abbiamo già accennato, per i normali file su disco non si ha
+mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
+prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
+tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
+ulteriori dettagli e qualche esempio in \secref{sec:TCP_sock_multiplexing}.
+
+
+\subsection{Le funzioni \func{select} e \func{pselect}}
+\label{sec:file_select}
+
+Il primo ad introdurre una interfaccia per l'\textit{I/O multiplexing} è stato
+BSD,\footnote{la funzione \func{select} è apparsa in BSD4.2 e standardizzata
+  in BSD4.4, ma è stata portata su tutti i sistemi che supportano i
+  \textit{socket}\index{socket}, compreso le varianti di System V.}  con la
+funzione \funcd{select}, il cui prototipo è:
 \begin{functions}
   \headdecl{sys/time.h}
   \headdecl{sys/types.h}
@@ -94,9 +109,10 @@ introdurre questa modalit
     caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
+    degli insiemi.
   \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo.
+  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo o
+    un valore non valido per \param{timeout}.
   \end{errlist}
   ed inoltre \errval{ENOMEM}.
 }
@@ -111,8 +127,8 @@ degli insiemi specificati (\param{readfds}, \param{writefds} e
 Per specificare quali file descriptor si intende \textsl{selezionare}, la
 funzione usa un particolare oggetto, il \textit{file descriptor set},
 identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
-file descriptor, (in maniera analoga a come un \textit{signal set}, vedi
-\secref{sec:sig_sigset}, identifica un insieme di segnali). Per la
+file descriptor, in maniera analoga a come un \textit{signal set} (vedi
+\secref{sec:sig_sigset}) identifica un insieme di segnali. Per la
 manipolazione di questi \textit{file descriptor set} si possono usare delle
 opportune macro di preprocessore:
 \begin{functions}
@@ -146,10 +162,13 @@ dar luogo a comportamenti non prevedibili.
 
 La funzione richiede di specificare tre insiemi distinti di file descriptor;
 il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
-effettuare una lettura, il secondo, \param{writefds}, per verificare la
-possibilità effettuare una scrittura ed il terzo, \param{exceptfds}, per
-verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su
-un \textit{socket}\index{socket}, vedi \secref{sec:TCP_urgent_data}).
+effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
+  tutti i casi in cui la successiva esecuzione di \func{read} risulti non
+  bloccante, quindi anche in caso di \textit{end-of-file}.} il secondo,
+\param{writefds}, per verificare la possibilità effettuare una scrittura ed il
+terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
+messaggi urgenti su un \textit{socket}\index{socket}, vedi
+\secref{sec:TCP_urgent_data}).
 
 Dato che in genere non si tengono mai sotto controllo fino a
 \const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
@@ -204,35 +223,121 @@ numero massimo di 1024 file descriptor per processo, adesso che il numero pu
 essere arbitario si viene a creare una dipendenza del tutto artificiale dalle
 dimensioni della struttura \type{fd\_set}, che può necessitare di essere
 estesa, con ulteriori perdite di prestazioni. 
-Per questo System V, invece di utilizzare l'interfaccia di \func{select}, che
-è una estensione creata nello sviluppo di BSD, ha introdotto una sua
-interfaccia per gestire l'\textit{I/O multiplexing}, basata sulla funzione
+
+Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
+  multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
+1003.1g-2000 e POSIX 1003.1-2001). La scelta è stata quella di seguire
+l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
+vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
+\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
+  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
+  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
+  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+  \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
+  \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
+  maggiore di 600.} il cui prototipo è:
+\begin{prototype}{sys/select.h}
+  {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
+    struct timespec *timeout, sigset\_t *sigmask)}
+  
+  Attende che uno dei file descriptor degli insiemi specificati diventi
+  attivo.
+  
+  \bodydesc{La funzione in caso di successo restituisce il numero di file
+    descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
+    caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
+    degli insiemi.
+  \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo o
+    un valore non valido per \param{timeout}.
+  \end{errlist}
+  ed inoltre \errval{ENOMEM}.}
+\end{prototype}
+
+La funzione è sostanzialmente identica a \func{select}, solo che usa una
+struttura \struct{timespec} (vedi \figref{fig:sys_timeval_struct}) per
+indicare con maggiore precisione il timeout e non ne aggiorna il valore in
+caso di interruzione. Inoltre prende un argomento aggiuntivo \param{sigmask}
+che è il puntatore ad una maschera di segnali (si veda
+\secref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
+immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
+funzione.
+
+L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
+race condition\index{race condition} quando ci si deve porre in attesa sia di
+un segnale che di dati.\footnote{in Linux però non è stata ancora introdotta
+  la relativa system call, pertanto la funzione è implementata nelle
+  \acr{glibc} attraverso \func{select} e la possibilità di race condition
+  permane.} La tecnica classica è quella di utilizzare il gestore per
+impostare una variabile globale e controllare questa nel corpo principale del
+programma; abbiamo visto in \secref{sec:sig_example} come questo lasci spazio
+a possibili race condition, per cui diventa essenziale utilizzare
+\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
+il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
+evitare l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe
+perso.
+
+Nel nostro caso il problema si pone quando oltre al segnale si devono tenere
+sotto controllo anche dei file descriptor con \func{select}, in questo caso si
+può fare conto sul fatto che all'arrivo di un segnale essa verrebbe interrotta
+e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
+alla gestione dati con un ciclo del tipo:
+\includecodesnip{listati/select_race.c} 
+qui però emerge una race condition, perché se il segnale arriva prima della
+chiamata a \func{select}, questa non verrà interrotta, e la ricezione del
+segnale non sarà rilevata.
+
+Per questo è stata introdotta \func{pselect}, che attraverso l'argomento
+\param{sigmask} permette di riabilitare la ricezione il segnale
+contestualmente all'esecuzione della funzione, e ribloccandolo non appena essa
+ritorna. In questo modo il precedente codice potrebbe essere essere modificato
+nel seguente modo: 
+\includecodesnip{listati/pselect_norace.c} 
+in questo caso utilizzando \var{oldmask} durante l'esecuzione di
+\func{pselect} la ricezione del segnale sarà abilitata, ed in caso di
+interruzione si potranno eseguire le relative operazioni.
+
+
+
+\subsection{La funzione \func{poll}}
+\label{sec:file_poll}
+
+System V, invece di utilizzare l'interfaccia di \func{select}, che è una
+estensione creata nello sviluppo di BSD, ha introdotto una sua interfaccia per
+gestire l'\textit{I/O multiplexing}, basata sulla funzione
 \funcd{poll},\footnote{la funzione è prevista dallo standard XPG4, ed è stata
-  introdotta in Linux come system call a partire dal kernel 2.1.23 e dalle
-  \acr{libc} 5.4.28.} il cui prototipo è:
+  introdotta in Linux come system call a partire dal kernel 2.1.23 ed inserita
+  nelle \acr{libc} 5.4.28.} il cui prototipo è:
 \begin{prototype}{sys/poll.h}
   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
   
   La funzione attende un cambiamento di stato per uno dei file descriptor
   specificati da \param{ufds}.
   
-\bodydesc{La funzione restituisce il numero di file descriptor con attività in
-  caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
-  restituito  -1 ed \var{errno} assumerà uno dei valori:
+  \bodydesc{La funzione restituisce il numero di file descriptor con attività
+    in caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
+    restituito -1 ed \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
     degli insiemi.
   \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] Il valore di \param{nfds} eccede il limite
+    \macro{RLIMIT\_NOFILE}.
   \end{errlist}
   ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
 \end{prototype}
 
-La funzione tiene sotto controllo un numero \param{ndfs} di file descriptor
-specificati attraverso un vettore di puntatori a strutture \struct{pollfd}, la
-cui definizione è riportata in \figref{fig:file_pollfd}.  Come \func{select}
-anche \func{poll} permette di interrompere l'attesa dopo un certo tempo, che
-va specificato attraverso \param{timeout} in numero di millisecondi (un valore
-negativo indica un'attesa indefinita).
+La funzione permette di tenere sotto controllo un certo numero \param{ndfs} di
+file descriptor, specificati attraverso un vettore di puntatori a strutture
+\struct{pollfd}.  Come \func{select} anche \func{poll} permette di
+interrompere l'attesa dopo un certo tempo, che va specificato attraverso
+l'argomento \param{timeout} in numero di millisecondi: un valore negativo
+indica un'attesa indefinita mentre si può usare un valore nullo per eseguire
+la funzione in modalità \textsl{non-bloccante}.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -246,11 +351,21 @@ negativo indica un'attesa indefinita).
 \end{figure}
 
 Per ciascun file da controllare deve essere opportunamente predisposta una
-struttura \struct{pollfd}; nel campo \var{fd} deve essere specificato il file
-descriptor, mentre nel campo \var{events} il tipo di evento su cui si vuole
-attendere; quest'ultimo deve essere specificato come maschera binaria dei
-primi tre valori riportati in \tabref{tab:file_pollfd_flags} (gli altri
-vengono utilizzati solo per \var{revents} come valori in uscita).
+struttura \struct{pollfd}, la cui definizione è riportata in
+\figref{fig:file_pollfd}.  La struttura prevede tre campi: il campo \var{fd}
+viene utilizzato per specificare il file descriptor relativo al file da
+controllare, mentre nel campo \var{events} deve essere specificata una
+maschera binaria data in ingresso che indichi il tipo di evento che si vuole
+controllare, il kernel restituirà il relativo risultato nel campo
+\var{revents}.
+
+Le costanti che definiscono i valori relativi ai bit usati nelle maschere
+binarie dei campi \var{events} e \var{revents} sono riportati in
+\tabref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
+per controllare l'attività in ingresso, nel secondo quelli per l'attività in
+uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
+nel campo \var{revents} per notificare delle condizioni di errore. 
 
 \begin{table}[htb]
   \centering
@@ -260,22 +375,20 @@ vengono utilizzati solo per \var{revents} come valori in uscita).
     \textbf{Flag}  & \textbf{Significato} \\
     \hline
     \hline
-    \const{POLLIN}    & È possibile la lettura immediata.\\
-    \const{POLLPRI}   & Sono presenti dati urgenti.\\
+    \const{POLLIN}    & È possibile la lettura.\\
+    \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\ 
+    \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari. \\
+    \const{POLLPRI}   & È possibile la lettura di dati urgenti.\\
+    \hline
     \const{POLLOUT}   & È possibile la scrittura immediata.\\
+    \const{POLLWRNORM}& È possibile la scrittura di dati normali.  \\ 
+    \const{POLLWRBAND}& È possibile la scrittura di dati prioritari. \\
     \hline
     \const{POLLERR}   & C'è una condizione di errore.\\
     \const{POLLHUP}   & Si è verificato un hung-up.\\
     \const{POLLNVAL}  & Il file descriptor non è aperto.\\
     \hline
-    \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\ 
-    \const{POLLRDBAND}& Sono disponibili in lettura dati ad alta 
-                        priorità. \\
-    \const{POLLWRNORM}& È possibile la scrittura di dati normali.  \\ 
-    \const{POLLWRBAND}& È possibile la scrittura di dati ad 
-                        alta priorità. \\
-    \const{POLLMSG}   & Un segnale \const{SIGPOLL} è arrivato alla
-                        cima dello stream (non usato).\\
+    \const{POLLMSG}   & Definito per compatobilità con SysV.\\
     \hline    
   \end{tabular}
   \caption{Costanti per l'identificazione dei vari bit dei campi
@@ -283,74 +396,44 @@ vengono utilizzati solo per \var{revents} come valori in uscita).
   \label{tab:file_pollfd_flags}
 \end{table}
 
-La funzione ritorna, restituendo il numero di file per i quali si è verificata
-una delle condizioni di attesa richieste od un errore. Lo stato dei file
-all'uscita della funzione viene restituito nel campo \var{revents} della
-relativa struttura \struct{pollfd}, che viene impostato alla maschera binaria
-dei valori riportati in \tabref{tab:file_pollfd_flags}, ed oltre alle tre
-condizioni specificate tramite \var{events} può riportare anche l'occorrere di
-una condizione di errore.
+Infine il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
+compatibilità con l'implementazione di SysV, dove indica segnale
+\const{SIGPOLL} è arrivato alla cima dello \textit{stream}. Gli
+\textit{stream} sono una interfaccia specifica di SysV non presente in Linux,
+e non hanno nulla a che fare con i file \textit{stream} delle librerie
+standard del C, è da questi che derivano i nomi delle costanti, in quanto per
+essi sono definite tre classi di dati: \textsl{normali}, \textit{prioritari}
+ed \textit{urgenti}. Nel caso di Linux la distinzione ha senso solo nel caso
+per i dati \textit{out-of-band} dei socket (vedi
+\secref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
+alle varie condizioni dei socket torneremo in \secref{sec:TCP_serv_poll}, dove
+vedremo anche un esempio del suo utilizzo.
 
-Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
-  multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
-1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni ad esso
-relative vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
-precedenti, ed aggiunge a \func{select} una nuova funzione
-\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
-  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
-  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
-  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
-  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
-  \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
-  \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
-  maggiore di 600.} il cui prototipo è:
-\begin{prototype}{sys/select.h}
-  {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
-    struct timespec *timeout, sigset\_t *sigmask)}
-  
-  Attende che uno dei file descriptor degli insiemi specificati diventi
-  attivo.
-  
-  \bodydesc{La funzione in caso di successo restituisce il numero di file
-    descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
-    caso \var{errno} assumerà uno dei valori:
-  \begin{errlist}
-  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo.
-  \end{errlist}
-  ed inoltre \errval{ENOMEM}.}
-\end{prototype}
+In caso di successo funzione ritorna restituendo il numero di file (un valore
+positivo) per i quali si è verificata una delle condizioni di attesa richieste
+o per i quali si è verificato un errore (nel qual caso vengono utilizzati i
+valori di \tabref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
+valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
+indica un errore nella chiamata, il cui codice viene riportato al solito
+tramite \var{errno}.
 
-La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \struct{timespec} per indicare con maggiore precisione il timeout e
-non ne aggiorna il valore in caso di interruzione, inoltre prende un argomento
-aggiuntivo \param{sigmask} che è il puntatore ad una maschera di segnali (si
-veda \secref{sec:sig_sigmask}). La maschera corrente viene sostituita da
-questa immediatamente prima di eseguire l'attesa, e ripristinata al ritorno
-della funzione.
 
-L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
-race condition\footnote{in Linux però, non esistendo una system call apposita,
-  la funzione è implementata nelle \acr{glibc} usando \func{select}, e la
-  possibilità di una race condition\index{race condition} resta.} quando si
-deve eseguire un test su una variabile assegnata da un gestore sulla base
-dell'occorrenza di un segnale per decidere se lanciare \func{select}. Fra il
-test e l'esecuzione è presente una finestra in cui potrebbe arrivare il
-segnale che non sarebbe rilevato; la race condition\index{race condition}
-diventa superabile disabilitando il segnale prima del test e riabilitandolo
-poi grazie all'uso di \param{sigmask}.
-
-Dato che l'I/O multiplexing serve a risolvere il problema di dover attendere
-la disponibilità di accesso ad un insieme di file, esso viene utilizzato
-prevalentemente per programmi in cui l'accesso ad un file descriptor può
-essere bloccante. Abbiamo già accennato come questo non avvenga mai per i
-normali file su disco; l'uso più comune di queste funzioni infatti è nei
-server di rete, in cui esse vengono utilizzate per tenere sotto controllo vari
-socket; pertanto ritorneremo su di esse con maggiori dettagli e con qualche
-esempio in \secref{sec:TCP_sock_multiplexing}.
+%\subsection{L'interfaccia di \textit{epoll}}
+%\label{sec:file_epoll}
+% placeholder ...
+
+
+
+
+\section{Altre modalità e funzioni di I/O avanzato}
+\label{sec:file_advanced_io}
 
+Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
+le più diffuse modalità di gestire l'I/O in situazioni complesse che
+coivolgono molti file, esistono altre modalità di gestione delle stesse
+problematiche, oltre che differenti interfacce per la gestione di altre
+problematiche avanzate riguardanti l'I/O su file, tratteremo tutto ciò in
+questa sezione.
 
 
 \subsection{L'I/O asincrono}
diff --git a/listati/ServEcho_second.c b/listati/ServEcho_second.c
new file mode 100644 (file)
index 0000000..c20c75e
--- /dev/null
@@ -0,0 +1,27 @@
+void ServEcho(int sockfd) {
+    char buffer[MAXLINE];
+    int nread, nwrite;
+    char debug[MAXLINE+20];
+    /* main loop, reading 0 char means client close connection */
+    while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
+       if (nread < 0) {
+           PrintErr("Errore in lettura");
+           return;
+       }
+       nwrite = FullWrite(sockfd, buffer, nread);
+       if (nwrite) {
+           PrintErr("Errore in scrittura");
+           return;
+       }
+       if (debugging) {
+           buffer[nread] = 0;
+           snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
+           if (demonize) {          /* daemon mode */
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+    }
+    return;
+}
index 35c5ef2cd5d73573ce76357c6ef9be0a5288ad56..5a95a989ba47f0a7fcea7a52aabb56c3d6e5b2f8 100644 (file)
@@ -1649,7 +1649,7 @@ compito del client leggere la risposta del server e stamparla sullo standard
 output.
 
 
-\subsection{Il client: prima versione}
+\subsection{Il client \textit{echo}: prima versione}
 \label{sec:TCP_echo_client}
 
 Il codice della prima versione del client per il servizio \textit{echo},
@@ -1731,7 +1731,7 @@ programma, usato per
 illustriamo immediatamente.
 
 
-\subsection{Il server: prima versione}
+\subsection{Il server \textit{echo}: prima versione}
 \label{sec:TCPsimp_server_main}
 
 La prima versione del server, contenuta nel file \file{TCP\_echod\_first.c}, è
@@ -2179,7 +2179,33 @@ ricevuto da \var{accept} viene convertito in una stringa che poi
 (\texttt{\small 34--39}) viene opportunamente stampata o sullo schermo o nei
 log.
 
+Infine come ulteriore miglioria si è perfezionata la funzione \code{ServEcho},
+sia per tenere conto della nuova funzionalità di debugging, che per effettuare
+un controllo in caso di errore; il codice della nuova versione è mostrato in
+\figref{fig:TCP_ServEcho_second}.
 
+\begin{figure}[!htb] 
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/ServEcho_second.c}
+  \end{minipage} 
+  \normalsize
+  \caption{Codice della seconda versione della funzione \code{ServEcho} per la
+    gestione del servizio \textit{echo}.}
+  \label{fig:TCP_ServEcho_second}
+\end{figure}
+
+Rispetto alla precedente versione di \figref{fig:TCP_ServEcho_first} in questo
+caso si è provveduto a controllare (\texttt{\small 7--10}) il valore di
+ritorno di \func{read} per rilevare un eventuale errore, in modo da stampare
+(\texttt{\small 8}) un messaggio di errore e ritornare (\texttt{\small 9})
+concludendo la connessione.
+
+Inoltre qualora sia stata attivata la funzionalità di debug (avvalorando
+\var{debugging} tramite l'apposita opzione \texttt{-d}) si provvederà a
+stampare (tenendo conto della modalità di invocazione del server, se
+interattiva o in forma di demone) il numero di byte e la stringa letta dal
+client (\texttt{\small 16--24}).
 
 
 \section{I vari scenari critici}
index 7351738281d804bdd6762a143c2b2c93ced5cb26..28b2318a09a93b8c6dfa69213563f4020d855c7c 100644 (file)
@@ -1,4 +1,4 @@
- %% tcpsockadv.tex
+%% tcpsockadv.tex
 %%
 %% Copyright (C) 2003 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
@@ -658,10 +658,38 @@ presenta un file descriptor aperto, e lo imposta (\texttt{\small 44}) come
 nuovo massimo, per poi tornare (\texttt{\small 44}) al ciclo principale con un
 \code{break}, e rieseguire \func{select}.
 
-Se infine si sono letti dei dati (ultimo caso rimasto) si potrà invocare
-(\texttt{\small 49}) \func{FullWrite} per riscriverli indietro sul socket in
-questione, avendo cura di uscire con un messaggio in caso di errore
-(\texttt{\small 50--53}).
+Se infine si sono effettivamente letti dei dati dal socket (ultimo caso
+rimasto) si potrà invocare immediatamente (\texttt{\small 49})
+\func{FullWrite} per riscriverli indietro sul socket stesso, avendo cura di
+uscire con un messaggio in caso di errore (\texttt{\small 50--53}). Si noti
+che nel ciclo si esegue una sola lettura, contrariamente a quanto fatto con la
+precedente versione (si riveda il codice di \secref{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à.
+
+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
+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
+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
+conseguente blocco del server su di una \func{write}.
+
+Le possibili soluzioni in questo caso sono quelle di ritornare ad eseguire il
+ciclo di risposta alle richieste all'interno di processi separati, utilizzare
+un timeout per le operazioni di scrittura, o eseguire queste ultime in
+modalità non bloccante, cocludendo le operazioni qualora non vadano a buon
+fine.