From d7db23a35bbd9c7465780719188709ca06e99eaf Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 6 Sep 2006 14:23:52 +0000 Subject: [PATCH] Altro materiale sparso, con alcune indicizzazioni (file descriptor set) che si erano perse per strada. --- fileadv.tex | 38 ++++++++++++----------- sockadv.tex | 16 ++++++++-- sockctrl.tex | 8 +++-- tcpsock.tex | 87 +++++++++++++++++++++++++++------------------------- 4 files changed, 85 insertions(+), 64 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index 58c7ee6..b65f922 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -127,10 +127,10 @@ 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 -\itindex{signal~set}\textit{signal set} (vedi sez.~\ref{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: +file descriptor, in maniera analoga a come un \itindex{signal~set} +\textit{signal set} (vedi sez.~\ref{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} \headdecl{sys/time.h} \headdecl{sys/types.h} @@ -185,7 +185,6 @@ ritorni; se impostato a \val{NULL} la funzione attende indefinitamente. Si pu specificare anche un tempo nullo (cioè una struttura \struct{timeval} con i campi impostati a zero), qualora si voglia semplicemente controllare lo stato corrente dei file descriptor. -\itindend{file~descriptor~set} La funzione restituisce il numero di file descriptor pronti,\footnote{questo è il comportamento previsto dallo standard, ma la standardizzazione della @@ -198,6 +197,8 @@ modificati. In caso di errore la funzione restituisce -1, ed i valori dei tre insiemi sono indefiniti e non si può fare nessun affidamento sul loro contenuto. +\itindend{file~descriptor~set} + In Linux \func{select} modifica anche il valore di \param{timeout}, impostandolo al tempo restante in caso di interruzione prematura; questo è utile quando la funzione viene interrotta da un segnale, in tal caso infatti @@ -291,25 +292,26 @@ interrotta, e la ricezione del segnale non sar Per questo è stata introdotta \func{pselect} che attraverso l'argomento \param{sigmask} permette di riabilitare la ricezione il segnale -contestualmente all'esecuzione della funzione,\footnote{in Linux però non è - presente la relativa system call, e la funzione è implementata nelle - \acr{glibc} attraverso \func{select} (vedi \texttt{man select\_tut}) per cui - la possibilità di \itindex{race~condition}\textit{race condition} permane; - esiste però una soluzione, chiamata \itindex{self-pipe trick} - \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi - sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della - stessa, e indicare l'arrivo di un segnale scrivendo sul capo in scrittura - all'interno del manipolatore; in questo modo anche se il segnale va perso - prima della chiamata di \func{select} questa lo riconoscerà comunque dalla - presenza di dati sulla pipe.} ribloccandolo non appena essa ritorna, così -che il precedente codice potrebbe essere riscritto nel seguente modo: +contestualmente all'esecuzione della funzione,\footnote{in Linux però, fino al + kernel 2.6.26, non è presente la relativa system call, e la funzione è + implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man + select\_tut}) per cui la possibilità di \itindex{race~condition} + \textit{race condition} permane; esiste però una soluzione, chiamata + \itindex{self-pipe trick} \textit{self-pipe trick}, che consiste nell'aprire + una pipe (vedi sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in + lettura della stessa, e indicare l'arrivo di un segnale scrivendo sul capo + in scrittura all'interno del manipolatore; in questo modo anche se il + segnale va perso prima della chiamata di \func{select} questa lo riconoscerà + comunque dalla presenza di dati sulla pipe.} ribloccandolo non appena essa +ritorna, così che il precedente codice potrebbe essere riscritto 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. % TODO pselect è stata introdotta nel kernel 2.6.16 (o 15 o 17?) insieme a -% ppoll mettere e verificare +% ppoll mettere e verificare, vedi articolo LWN http://lwn.net/Articles/176750/ \subsection{La funzione \func{poll}} diff --git a/sockadv.tex b/sockadv.tex index 25ca699..f501771 100644 --- a/sockadv.tex +++ b/sockadv.tex @@ -59,13 +59,23 @@ fig.~\ref{fig:sock_extended_err_struct}. -\subsection{I dati \textit{out-of-band}} +\subsection{I \textsl{dati urgenti} o \textit{out-of-band}} \label{sec:TCP_urgent_data} \itindbeg{out-of-band} -Una caratteristica speciale dei socket TCP è quella della presenza dei -cosiddetti dati \textit{out-of-band} ... +Una caratteristica particolare dei socket TCP è quella che consente di inviare +all'altro capo della comunicazione una sorta di messaggio privilegiato, che si +richide che sia trattato il prima possibile. Si fa riferimento a questa +funzionalità come all'invio dei cosiddetti \textsl{dati urgenti} (o +\textit{udernt data}); tavolta essi chiamati anche dati \textit{out-of-band} +poiché, come vedremo più anvati, possono essere letti anche al di fuori del +flusso di dati normale. + +Come già accennato in sez.~\ref{sec:file_multiplexing} la presenza di dati +urgenti viene rilevata in maniera specifica sia di \func{select} (con il +\itindex{file~descriptor~set} \textit{file descriptor set} \param{exceptfds}) +che da \func{poll} (con la condizione \const{POLLRDBAND}). Le modalità di lettura dei dati urgenti sono due, la prima e più comune diff --git a/sockctrl.tex b/sockctrl.tex index 2946d86..8bc4d03 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2274,7 +2274,11 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: \item[\const{SO\_ERROR}] questa opzione riceve un errore presente sul socket; può essere utilizzata soltanto con \func{getsockopt} e prende per - \param{optval} un valore intero. + \param{optval} un valore intero, nel quale viene restituito il codice di + errore, e la condizione di errore sul socket viene cancellata. Viene + usualmente utilizzata per ricevere il codice di errore, come accennato in + sez.~\ref{sec:TCP_sock_select}, quando si sta osservando il socket con una + \func{select} che ritorna a causa dello stesso. \end{basedescript} @@ -3259,7 +3263,7 @@ sono le seguenti: soltanto una etichetta associata a detto \textsl{indice}, che permette di rendere più comprensibile l'indicazione dell'interfaccia all'interno dei comandi; si può ottenere un elenco delle interfacce che contiene anche il - valore del relativo indice usando il comando \cmd{ip link}.} + valore del relativo indice usando il comando \cmd{ip link}. \item[\const{SIOCGIFINDEX}] restituisce nel campo \var{ifr\_ifindex} il valore numerico dell'indice dell'interfaccia specificata con \var{ifr\_name}, è in diff --git a/tcpsock.tex b/tcpsock.tex index 7535d61..d3d1f55 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -2754,14 +2754,16 @@ 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. + + In quell'occasione non abbiamo però definito cosa si intende per pronto, infatti per dei normali file, o anche per delle pipe, la condizione di essere pronti per la lettura o la scrittura è ovvia; invece lo è molto meno nel caso dei socket, visto che possono intervenire tutte una serie di possibili condizioni di errore dovute alla rete. Occorre allora specificare chiaramente quali sono le condizioni per cui un socket risulta essere ``\textsl{pronto}'' -quando viene passato come membro di uno dei tre \textit{file descriptor set} -usati da \func{select}. +quando viene passato come membro di uno dei tre \itindex{file~descriptor~set} +\textit{file descriptor set} usati da \func{select}. Le condizioni che fanno si che la funzione \func{select} ritorni segnalando che un socket (che sarà riportato nel primo insieme di file descriptor) è @@ -2785,8 +2787,8 @@ pronto per la lettura sono le seguenti: non si bloccherà ma restituirà una condizione di errore (ad esempio \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 errori pendenti su un socket usando l'opzione - \const{SO\_ERROR}. + estrarre e cancellare gli errori pendenti su un socket senza usare + \func{read} usando l'opzione \const{SO\_ERROR}. \item quando si sta utilizzando un \textit{listening socket} ed ci sono delle connessioni completate. In questo caso la funzione \func{accept} non si bloccherà.\footnote{in realtà questo non è sempre vero, come accennato in @@ -2900,26 +2902,27 @@ codice completo si trova nel file \file{TCP\_echo\_third.c} dei sorgenti allegati alla guida. In questo caso la funzione comincia (\texttt{\small 8--9}) con l'azzeramento -del file descriptor set \var{fset} e l'impostazione del valore \var{maxfd}, da -passare a \func{select} come massimo per il numero di file descriptor. Per -determinare quest'ultimo si usa la macro \code{max} definita nel nostro file -\file{macro.h} che raccoglie una collezione di macro di preprocessore di varia -utilità. +del \itindex{file~descriptor~set} \textit{file descriptor set} \var{fset} e +l'impostazione del valore \var{maxfd}, da passare a \func{select} come massimo +per il numero di file descriptor. Per determinare quest'ultimo si usa la macro +\code{max} definita nel nostro file \file{macro.h} che raccoglie una +collezione di macro di preprocessore di varia utilità. La funzione prosegue poi (\texttt{\small 10--41}) con il ciclo principale, che viene ripetuto indefinitamente. Per ogni ciclo si reinizializza -(\texttt{\small 11--12}) il file descriptor set, impostando i valori per il -file descriptor associato al socket \var{socket} e per lo 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. +(\texttt{\small 11--12}) il \itindex{file~descriptor~set} \textit{file + descriptor set}, impostando i valori per il file descriptor associato al +socket \var{socket} e per lo 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. 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 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. +il solo \itindex{file~descriptor~set} \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. Al ritorno di \func{select} si provvede a controllare quale dei due file descriptor presenta attività in lettura, cominciando (\texttt{\small 14--24}) @@ -3196,7 +3199,7 @@ prima (\texttt{\small 19}) si imposta opportunamente \var{eof} ad un valore non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si usa la macro \macro{FD\_CLR} per togliere lo standard input dal file -descriptor set. +descriptor set. \itindex{file~descriptor~set} 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 @@ -3278,14 +3281,15 @@ aperti viene impostato a quello del socket in ascolto,\footnote{in quanto esso 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. +costruzione del \itindex{file~descriptor~set} \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 +\itindex{file~descriptor~set} \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}, per cui il kernel associa sempre ad ogni nuovo file @@ -3334,14 +3338,14 @@ vi 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 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. +saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del +\itindex{file~descriptor~set} 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. Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore dell'indice \var{i} per posizionarsi sul primo valore possibile per un file @@ -3416,7 +3420,8 @@ maggior parte dei casi, in quanto essa 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}.} + delle limitazioni dovute all'uso dei \itindex{file~descriptor~set} + \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} @@ -3550,11 +3555,11 @@ effettuarne la riscrittura all'indietro, con il solito controllo ed eventuale uscita e notifica in caso si 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}; la -sola differenza significativa è che in questo caso non c'è bisogno di -rigenerare i file descriptor set in quanto l'uscita è indipendente dai dati in -ingresso. Si applicano comunque anche a questo server le considerazioni finali -di sez.~\ref{sec:TCP_serv_select}. +fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; +la sola differenza significativa è che in questo caso non c'è bisogno di +rigenerare i \itindex{file~descriptor~set} file descriptor set in quanto +l'uscita è indipendente dai dati in ingresso. Si applicano comunque anche a +questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}. % LocalWords: socket TCP client dell'I multiplexing stream three way handshake -- 2.30.2