- /* initialize all needed variables */
+...
poll_set = (struct pollfd *) malloc(n * sizeof(struct pollfd));
max_fd = list_fd; /* maximum now is listening socket */
- for (i=0; i<n; i++) {
+ for (i=0; i<n; i++) { /* initialize poll set */
poll_set[i].fd = -1;
poll_set[i].events = POLLRDNORM;
}
- poll_set[max_fd].fd = list_fd;
- /* main loop, wait for connection and data inside a select */
- while (1) {
- while ( ((n = poll(poll_set, max_fd + 1, -1)) < 0)
- && (errno == EINTR)); /* wait for data or connection */
+ poll_set[max_fd].fd = list_fd;
+ while (1) { /* main loop, wait for connection and data inside a poll */
+ while ( ((n=poll(poll_set, max_fd + 1, -1)) < 0) && (errno == EINTR));
if (n < 0) { /* on real error exit */
PrintErr("poll error");
exit(1);
}
}
}
- exit(0); /* normal exit, never reached */
+...
--- /dev/null
+struct __res_state;
+typedef struct __res_state *res_state;
- extern struct state _res;
+extern struct __res_state _res;
memset(fd_open, 0, FD_SETSIZE); /* clear array of open files */
max_fd = list_fd; /* maximum now is listening socket */
fd_open[max_fd] = 1;
- /* main loop, wait for connection and data inside a select */
- while (1) {
- FD_ZERO(&fset); /* clear fd_set */
- for (i = list_fd; i <= max_fd; i++) { /* initialize fd_set */
+ while (1) { /* main loop, wait for connection and data inside a select */
+ FD_ZERO(&fset); /* clear fd_set */
+ for (i = list_fd; i <= max_fd; i++) /* initialize fd_set */
if (fd_open[i] != 0) FD_SET(i, &fset);
- }
while ( ((n = select(max_fd + 1, &fset, NULL, NULL, NULL)) < 0)
&& (errno == EINTR)); /* wait for data or connection */
if (n < 0) { /* on real error exit */
fd_open[fd] = 1; /* set new connection socket */
if (max_fd < fd) max_fd = fd; /* if needed set new maximum */
}
- /* loop on open connections */
- i = list_fd; /* first socket to look */
- while (n != 0) { /* loop until active */
- i++; /* start after listening socket */
+ i = list_fd; /* first socket to look */
+ while (n != 0) { /* loop on open connections */
+ i++; /* start after listening socket */
if (fd_open[i] == 0) continue; /* closed, go next */
if (FD_ISSET(i, &fset)) { /* if active process it*/
n--; /* decrease active */
% http://lwn.net/Articles/531498/
+% TODO trattare le funzioni di protezione della memoria pkey_alloc, pkey_free,
+% pkey_mprotect, introdotte con il kernel 4.8, vedi
+% http://lwn.net/Articles/689395/ e Documentation/x86/protection-keys.txt
+
%TODO trattare kcmp aggiunta con il kernel 3.5, vedi
% https://lwn.net/Articles/478111/
Qui vanno spiegati i terminali virtuali, \file{/dev/pty} e compagnia.
% vedi man pts
+% vedi
\subsection{Allocazione dei terminali virtuali}
% TODO le ioctl dei terminali (man tty_ioctl)
% e http://www.net-security.org/article.php?id=83
% TODO trattare \func{posix\_openpt}
+% vedi http://lwn.net/Articles/688809/,
+% http://man7.org/linux/man-pages/man3/ptsname.3.html
% TODO materiale sulle seriali
\subsection{La struttura del \textit{resolver}}
\label{sec:sock_resolver}
-\itindbeg{resolver}
-La risoluzione dei nomi è associata tradizionalmente al servizio del
-\textit{Domain Name Service} che permette di identificare le macchine su
-internet invece che per numero IP attraverso il relativo \textsl{nome a
- dominio}.\footnote{non staremo ad entrare nei dettagli della definizione di
- cosa è un nome a dominio, dandolo per noto, una introduzione alla
- problematica si trova in \cite{AGL} (cap.~9) mentre per una trattazione
- approfondita di tutte le problematiche relative al DNS si può fare
- riferimento a \cite{DNSbind}.} In realtà per DNS si intendono spesso i
-server che forniscono su internet questo servizio, mentre nel nostro caso
-affronteremo la problematica dal lato client, di un qualunque programma che
-necessita di compiere questa operazione.
+\itindbeg{resolver} La risoluzione dei nomi è associata tradizionalmente al
+servizio del \itindex{Domain~Name~Service} \textit{Domain Name Service} che
+permette di identificare le macchine su internet invece che per numero IP
+attraverso il relativo \textsl{nome a dominio}.\footnote{non staremo ad
+ entrare nei dettagli della definizione di cosa è un nome a dominio, dandolo
+ per noto, una introduzione alla problematica si trova in \cite{AGL} (cap.~9)
+ mentre per una trattazione approfondita di tutte le problematiche relative
+ al DNS si può fare riferimento a \cite{DNSbind}.} In realtà per DNS si
+intendono spesso i server che forniscono su internet questo servizio, mentre
+nel nostro caso affronteremo la problematica dal lato client, di un qualunque
+programma che necessita di compiere questa operazione.
\begin{figure}[!htb]
\centering \includegraphics[width=11cm]{img/resolver}
\textit{netgroup}) varie macchine, centralizzando i servizi di definizione
di utenti e gruppi e di autenticazione, oggi è sempre più spesso sostituito
da LDAP.} o come quelli dei protocolli e dei servizi che sono mantenuti nei
-file statici \conffile{/etc/protocols} e \conffile{/etc/services}. Molte di
-queste informazioni non si trovano su un DNS, ma in una rete locale può essere
-molto utile centralizzare il mantenimento di alcune di esse su opportuni
-server. Inoltre l'uso di diversi supporti possibili per le stesse
+file statici \conffile{/etc/protocols} e \conffile{/etc/services}.
+
+Molte di queste informazioni non si trovano su un DNS, ma in una rete locale
+può essere molto utile centralizzare il mantenimento di alcune di esse su
+opportuni server. Inoltre l'uso di diversi supporti possibili per le stesse
informazioni (ad esempio il nome delle macchine può essere mantenuto sia
tramite \conffile{/etc/hosts}, che con il DNS, che con NIS) comporta il
-problema dell'ordine in cui questi vengono interrogati.\footnote{con le
- implementazioni classiche i vari supporti erano introdotti modificando
- direttamente le funzioni di libreria, prevedendo un ordine di interrogazione
- predefinito e non modificabile (a meno di una ricompilazione delle librerie
- stesse).}
+problema dell'ordine in cui questi vengono interrogati. Con le implementazioni
+classiche i vari supporti erano introdotti modificando direttamente le
+funzioni di libreria, prevedendo un ordine di interrogazione predefinito e non
+modificabile (a meno di una ricompilazione delle librerie stesse).
+
+\itindbeg{Name~Service~Switch~(NSS)}
-\itindbeg{Name~Service~Switch~(NSS)}
Per risolvere questa serie di problemi la risoluzione dei nomi a dominio
-eseguirà dal \textit{resolver} è stata inclusa all'interno di un meccanismo
+eseguità dal \textit{resolver} è stata inclusa all'interno di un meccanismo
generico per la risoluzione di corrispondenze fra nomi ed informazioni ad essi
-associate chiamato \textit{Name Service Switch}\footnote{il sistema è stato
- introdotto la prima volta nelle librerie standard di Solaris, le \acr{glibc}
- hanno ripreso lo stesso schema, si tenga presente che questo sistema non
- esiste per altre librerie standard come le \acr{libc5} o le \acr{uclib}.}
-cui abbiamo accennato anche in sez.~\ref{sec:sys_user_group} per quanto
-riguarda la gestione dei dati associati a utenti e gruppi. Il \textit{Name
- Service Switch} (cui spesso si fa riferimento con l'acronimo NSS) è un
-sistema di librerie dinamiche che permette di definire in maniera generica sia
-i supporti su cui mantenere i dati di corrispondenza fra nomi e valori
-numerici, sia l'ordine in cui effettuare le ricerche sui vari supporti
+associate chiamato \textit{Name Service Switch} cui abbiamo accennato anche in
+sez.~\ref{sec:sys_user_group} per quanto riguarda la gestione dei dati
+associati a utenti e gruppi. Il sistema è stato introdotto la prima volta
+nelle librerie standard di Solaris e le \acr{glibc} hanno ripreso lo stesso
+schema; si tenga presente che questo sistema non esiste per altre librerie
+standard come le \acr{libc5} o le \acr{uclib}.
+
+Il \textit{Name Service Switch} (cui spesso si fa riferimento con l'acronimo
+NSS) è un sistema di librerie dinamiche che permette di definire in maniera
+generica sia i supporti su cui mantenere i dati di corrispondenza fra nomi e
+valori numerici, sia l'ordine in cui effettuare le ricerche sui vari supporti
disponibili. Il sistema prevede una serie di possibili classi di
corrispondenza, quelle attualmente definite sono riportate in
tab.~\ref{tab:sys_NSS_classes}.
% TODO rivedere meglio la tabella
Il sistema del \textit{Name Service Switch} è controllato dal contenuto del
-file \conffile{/etc/nsswitch.conf}; questo contiene una riga\footnote{seguendo
- una convezione comune per i file di configurazione le righe vuote vengono
- ignorate e tutto quello che segue un carattere ``\texttt{\#}'' viene
- considerato un commento.} di configurazione per ciascuna di queste classi,
-che viene inizia col nome di tab.~\ref{tab:sys_NSS_classes} seguito da un
-carattere ``\texttt{:}'' e prosegue con la lista dei \textsl{servizi} su cui
-le relative informazioni sono raggiungibili, scritti nell'ordine in cui si
-vuole siano interrogati.
+file \conffile{/etc/nsswitch.conf}; questo contiene una riga di configurazione
+per ciascuna di queste classi, che viene inizia col nome di
+tab.~\ref{tab:sys_NSS_classes} seguito da un carattere ``\texttt{:}'' e
+prosegue con la lista dei \textsl{servizi} su cui le relative informazioni
+sono raggiungibili, scritti nell'ordine in cui si vuole siano interrogati.
Ogni servizio è specificato a sua volta da un nome, come \texttt{file},
\texttt{dns}, \texttt{db}, ecc. che identifica la libreria dinamica che
In ogni caso, qualunque sia la modalità con cui ricevono i dati o il supporto
su cui vengono mantenuti, e che si usino o meno funzionalità aggiuntive
-fornire dal sistema del \textit{Name Service Switch}, dal punto di vista di un
+fornite dal sistema del \textit{Name Service Switch}, dal punto di vista di un
programma che deve effettuare la risoluzione di un nome a dominio, tutto
quello che conta sono le funzioni classiche che il \textit{resolver} mette a
-disposizione,\footnote{è cura della implementazione fattane nelle \acr{glibc}
- tenere conto della presenza del \textit{Name Service Switch}.} e sono queste
-quelle che tratteremo nelle sezioni successive.
+disposizione (è cura delle \acr{glibc} tenere conto della presenza del
+\textit{Name Service Switch}) e sono queste quelle che tratteremo nelle
+sezioni successive.
+
\itindend{Name~Service~Switch~(NSS)}
\label{sec:sock_resolver_functions}
Prima di trattare le funzioni usate normalmente nella risoluzione dei nomi a
-dominio conviene trattare in maniera più dettagliata il meccanismo principale
-da esse utilizzato e cioè quello del servizio DNS. Come accennato questo,
-benché in teoria sia solo uno dei possibili supporti su cui mantenere le
-informazioni, in pratica costituisce il meccanismo principale con cui vengono
-risolti i nomi a dominio. Per questo motivo esistono una serie di funzioni di
-libreria che servono specificamente ad eseguire delle interrogazioni verso un
-server DNS, funzioni che poi vengono utilizzate per realizzare le funzioni
-generiche di libreria usate anche dal sistema del \textit{resolver}.
+dominio conviene trattare in maniera più dettagliata il servizio DNS. Come
+accennato questo, benché esso in teoria sia solo uno dei possibili supporti su
+cui mantenere le informazioni, in pratica costituisce il meccanismo principale
+con cui vengono risolti i nomi a dominio. Inolte esso può fornire anche
+ulteriori informazioni oltre relative alla risoluzione dei nomi a dominio.
+Per questo motivo esistono una serie di funzioni di libreria che servono
+specificamente ad eseguire delle interrogazioni verso un server DNS, funzioni
+che poi vengono utilizzate anche per realizzare le funzioni generiche di
+libreria usate dal sistema del \textit{resolver}.
Il sistema del DNS è in sostanza di un database distribuito organizzato in
maniera gerarchica, i dati vengono mantenuti in tanti server distinti ciascuno
potrà delegare la risoluzione di un eventuale sotto-dominio di terzo livello ad
un altro server ancora.
-In realtà un server DNS è in grado di fare altro rispetto alla risoluzione di
-un nome a dominio in un indirizzo IP; ciascuna voce nel database viene
-chiamata \textit{resource record}, e può contenere diverse informazioni. In
-genere i \textit{resource record} vengono classificati per la \textsl{classe
- di indirizzi} cui i dati contenuti fanno riferimento, e per il \textsl{tipo}
-di questi ultimi.\footnote{ritroveremo classi di indirizzi e tipi di record
- più avanti in tab.~\ref{tab:DNS_address_class} e
- tab.~\ref{tab:DNS_record_type}.} Oggigiorno i dati mantenuti nei server DNS
+Come accennato un server DNS è in grado di fare molto altro rispetto alla
+risoluzione di un nome a dominio in un indirizzo IP: ciascuna voce nel
+database viene chiamata \textit{resource record}, e può contenere diverse
+informazioni. In genere i \textit{resource record} vengono classificati per la
+\textsl{classe di indirizzi} cui i dati contenuti fanno riferimento, e per il
+\textsl{tipo} di questi ultimi (ritroveremo classi di indirizzi e tipi di
+record più avanti in tab.~\ref{tab:DNS_address_class} e
+tab.~\ref{tab:DNS_record_type}). Oggigiorno i dati mantenuti nei server DNS
sono quasi esclusivamente relativi ad indirizzi internet, per cui in pratica
viene utilizzata soltanto una classe di indirizzi; invece le corrispondenze
fra un nome a dominio ed un indirizzo IP sono solo uno fra i vari tipi di
informazione che un server DNS fornisce normalmente.
L'esistenza di vari tipi di informazioni è un altro dei motivi per cui il
-\textit{resolver} prevede, rispetto a quelle relative alla semplice
-risoluzione dei nomi, un insieme di funzioni specifiche dedicate
-all'interrogazione di un server DNS; la prima di queste funzioni è
-\funcd{res\_init}, il cui prototipo è:
-\begin{functions}
- \headdecl{netinet/in.h} \headdecl{arpa/nameser.h} \headdecl{resolv.h}
- \funcdecl{int res\_init(void)}
-
-Inizializza il sistema del \textit{resolver}.
+\textit{resolver} prevede, oltre a quelle relative alla semplice risoluzione
+dei nomi, un insieme di funzioni specifiche dedicate all'interrogazione di un
+server DNS, tutte nella forma \texttt{res\_}\textsl{\texttt{nome}}.
+Tradizionalmente la prima di queste funzioni è \funcd{res\_init}, il cui
+prototipo è:
-\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore.}
-\end{functions}
+\begin{funcproto}{
+\fhead{netinet/in.h}
+\fhead{arpa/nameser.h}
+\fhead{resolv.h}
+\fdecl{int res\_init(void)}
+\fdesc{Inizializza il sistema del \textit{resolver}.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore.
+}
+\end{funcproto}
La funzione legge il contenuto dei file di configurazione (i già citati
\file{resolv.conf} e \file{host.conf}) per impostare il dominio di default,
funzione direttamente in quanto viene automaticamente chiamata la prima volta
che si esegue una delle altre.
-Le impostazioni e lo stato del \textit{resolver} vengono mantenuti in una
-serie di variabili raggruppate nei campi di una apposita struttura \var{\_res}
-usata da tutte queste funzioni. Essa viene definita in \headfiled{resolv.h} ed
-è utilizzata internamente alle funzioni essendo definita come variabile
-globale; questo consente anche di accedervi direttamente all'interno di un
-qualunque programma, una volta che la sia opportunamente dichiarata come:
+Le impostazioni e lo stato del \textit{resolver} inizializzati da
+\func{res\_init} vengono mantenuti in una serie di variabili raggruppate nei
+campi di una apposita struttura \var{\_res} usata da tutte queste
+funzioni. Essa viene definita in \headfiled{resolv.h} ed è utilizzata
+internamente alle funzioni essendo definita come variabile globale; questo
+consente anche di accedervi direttamente all'interno di un qualunque
+programma, una volta che la sia opportunamente dichiarata come:
\includecodesnip{listati/resolv_option.c}
-Tutti i campi della struttura sono ad uso interno, e vengono usualmente
-inizializzati da \func{res\_init} in base al contenuto dei file di
+Dato che l'uso di una variabile globale rende tutte le funzioni classiche non
+rientranti, con l'uscita di BIND 8.2 è stata introdotta una nuova interfaccia
+in cui tutte le nuove funzioni (il cui nome è ottenuto apponendo una
+``\texttt{n}'' al nome di quella tradizionale nella forma
+\texttt{res\_n\textsl{nome}}). Tutte le nuove funzioni prendono un primo
+argomento aggiuntivo, \param{statep}, che punti ad una struttura dello stesso
+tipo, che verrà usato per mantenere lo stato del \textit{resolver} e potrà
+essere usata senza problemi anche con programmi \textit{multithread}. Anche
+in questo caso per poterlo utilizzare occorrerà una opportuna dichiarazione
+del tipo di dato con:
+\includecodesnip{listati/resolv_newoption.c}
+e la nuova funzione che utilizzata per inizializzare il \textit{resolver} (che
+come la precedente viene chiamata automaticamente dalle altre funzioni) è
+\funcd{res\_ninit} il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{netinet/in.h}
+\fhead{arpa/nameser.h}
+\fhead{resolv.h}
+\fdecl{int res\_ninit(res\_state statep)}
+\fdesc{Inizializza il sistema del \textit{resolver}.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore.
+}
+\end{funcproto}
+
+Indipendentemente da quale versione delle funzioni si usino, tutti i campi
+della struttura sono ad uso interno, e vengono usualmente inizializzate da
+\func{res\_init} o \func{res\_ninit} in base al contenuto dei file di
configurazione e ad una serie di valori di default. L'unico campo che può
essere utile modificare è \var{\_res.options}, una maschera binaria che
contiene una serie di bit di opzione che permettono di controllare il
-comportamento del \textit{resolver}.
+comportamento del \textit{resolver}.
\begin{table}[htb]
\centering
controlla quante volte viene ripetuto il tentativo di connettersi ad un server
DNS prima di dichiarare fallimento; il valore di default è 4, un valore nullo
significa bloccare l'uso del DNS. Infine con \envvar{RES\_TIMEOUT} si
-soprassiede il valore del campo \var{retrans},\footnote{preimpostato al valore
- della omonima costante \const{RES\_TIMEOUT} di \headfile{resolv.h}.} che è
-il valore preso come base (in numero di secondi) per definire la scadenza di
-una richiesta, ciascun tentativo di richiesta fallito viene ripetuto
-raddoppiando il tempo di scadenza per il numero massimo di volte stabilito da
+soprassiede il valore del campo \var{retrans} (preimpostato al valore della
+omonima costante \const{RES\_TIMEOUT} di \headfile{resolv.h}) che è il valore
+preso come base (in numero di secondi) per definire la scadenza di una
+richiesta, ciascun tentativo di richiesta fallito viene ripetuto raddoppiando
+il tempo di scadenza per il numero massimo di volte stabilito da
\texttt{RES\_RETRY}.
-La funzione di interrogazione principale è \funcd{res\_query}, che serve ad
-eseguire una richiesta ad un server DNS per un nome a dominio
-\textsl{completamente specificato} (quello che si chiama
-\itindex{Fully~Qualified~Domain~Name~(FQDN)} FQDN, \textit{Fully Qualified
- Domain Name}); il suo prototipo è:
-
-\begin{functions}
-\headdecl{netinet/in.h}
-\headdecl{arpa/nameser.h}
-\headdecl{resolv.h}
-\funcdecl{int res\_query(const char *dname, int class, int type,
+La funzione di interrogazione principale è \funcd{res\_query}
+(\funcd{res\_nquery} per la nuova interfaccia), che serve ad eseguire una
+richiesta ad un server DNS per un nome a dominio \textsl{completamente
+ specificato} (quello che si chiama
+\itindex{Fully~Qualified~Domain~Name~(FQDN)} FQDN, \textit{Fully Qualified
+ Domain Name}); il loro prototipo è:
+
+\begin{funcproto}{
+\fhead{netinet/in.h}
+\fhead{arpa/nameser.h}
+\fhead{resolv.h}
+\fdecl{int res\_query(const char *dname, int class, int type,
unsigned char *answer, int anslen)}
+\fdecl{int res\_nquery(res\_state statep, const char *dname, int class, int
+ type, \\
+ \phantom{int res\_nquery(}unsigned char *answer, int anslen)}
+\fdesc{Esegue una interrogazione al DNS.}
+}
+{Le funzioni ritornano un valore positivo pari alla lunghezza dei dati scritti
+ nel buffer \param{answer} in caso di successo e $-1$ per un errore.
+}
+\end{funcproto}
- Esegue una interrogazione al DNS.
-
-\bodydesc{La funzione restituisce un valore positivo pari alla lunghezza dei
- dati scritti nel buffer \param{answer} in caso di successo e -1 in caso di
- errore.}
-\end{functions}
-
-La funzione esegue una interrogazione ad un server DNS relativa al nome da
+Le funzioni eseguono una interrogazione ad un server DNS relativa al nome da
risolvere passato nella stringa indirizzata da \param{dname}, inoltre deve
essere specificata la classe di indirizzi in cui eseguire la ricerca con
\param{class}, ed il tipo di \textit{resource record} che si vuole ottenere
lunghezza \param{anslen} puntato da \param{answer} che si sarà opportunamente
allocato in precedenza.
-
-Una seconda funzione di ricerca, analoga a \func{res\_query}, che prende gli
-stessi argomenti, ma che esegue l'interrogazione con le funzionalità
+Una seconda funzione di ricerca analoga a \func{res\_query}, che prende gli
+stessi argomenti ma che esegue l'interrogazione con le funzionalità
addizionali previste dalle due opzioni \const{RES\_DEFNAMES} e
-\const{RES\_DNSRCH}, è \funcd{res\_search}, il cui prototipo è:
-\begin{functions}
-\headdecl{netinet/in.h}
-\headdecl{arpa/nameser.h}
-\headdecl{resolv.h}
-\funcdecl{int res\_search(const char *dname, int class, int type,
- unsigned char *answer, int anslen)}
-
- Esegue una interrogazione al DNS.
-
- \bodydesc{La funzione restituisce un valore positivo pari alla lunghezza dei
- dati scritti nel buffer \param{answer} in caso di successo e -1 in caso di
- errore.}
-\end{functions}
+\const{RES\_DNSRCH}, è \funcd{res\_search} (\funcd{res\_nsearch} per la nuova
+interfaccia), il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{netinet/in.h}
+\fhead{arpa/nameser.h}
+\fhead{resolv.h}
+\fdecl{int res\_search(const char *dname, int class, int type,
+ unsigned char *answer, \\
+ \phantom{int res\_search}int anslen)}
+\fdecl{int res\_nsearch(res\_state statep, const char *dname, int class,
+ int type, \\
+ \phantom{int res\_nsearch(}unsigned char *answer, int anslen)}
+\fdesc{Esegue una interrogazione al DNS.}
+}
+{Le funzioni ritornano un valore positivo pari alla lunghezza dei dati scritti
+ nel buffer \param{answer} in caso di successo e $-1$ per un errore.
+}
+\end{funcproto}
In sostanza la funzione ripete una serie di chiamate a \func{res\_query}
-aggiungendo al nome contenuto nella stringa \param{dname} il dominio di
-default da cercare, fermandosi non appena trova un risultato. Il risultato di
-entrambe le funzioni viene scritto nel formato opportuno (che sarà diverso a
-seconda del tipo di record richiesto) nel buffer di ritorno; sarà compito del
-programma (o di altre funzioni) estrarre i relativi dati, esistono una serie
-di funzioni interne usate per la scansione di questi dati, per chi fosse
-interessato una trattazione dettagliata è riportata nel quattordicesimo
-capitolo di \cite{DNSbind}.
+(\func{res\_nquery}) aggiungendo al nome contenuto nella stringa \param{dname}
+il dominio di default da cercare, fermandosi non appena trova un risultato.
+Il risultato di entrambe le funzioni viene scritto nel formato opportuno (che
+sarà diverso a seconda del tipo di record richiesto) nel buffer di ritorno;
+sarà compito del programma (o di altre funzioni) estrarre i relativi dati,
+esistono una serie di funzioni interne usate per la scansione di questi dati,
+per chi fosse interessato una trattazione dettagliata è riportata nel
+quattordicesimo capitolo di \cite{DNSbind}.
Le classi di indirizzi supportate da un server DNS sono tre, ma di queste in
pratica oggi viene utilizzata soltanto quella degli indirizzi internet; le
% LocalWords: newlen ENOTDIR EINVAL ENOMEM linux array oldvalue paging stack
% LocalWords: TCP shell Documentation ostype hostname osrelease version mount
% LocalWords: const source filesystemtype mountflags ENODEV ENOTBLK block read
-% LocalWords: device EBUSY only EACCES NODEV ENXIO major RTSIG syscall PID NSS
+% LocalWords: device EBUSY only EACCES NODEV ENXIO major RTSIG syscall PID
% LocalWords: number EMFILE dummy ENAMETOOLONG ENOENT ELOOP virtual devfs MGC
% LocalWords: magic MSK RDONLY NOSUID suid sgid NOEXEC SYNCHRONOUS REMOUNT MNT
% LocalWords: MANDLOCK mandatory locking WRITE APPEND append IMMUTABLE NOATIME
\includecodesample{listati/select_echod.c}
\end{minipage}
\normalsize
- \caption{La sezione principale del codice della nuova versione di server
- \textit{echo} basati sull'uso della funzione \func{select}.}
+ \caption{La sezione principale della nuova versione di server
+ \textit{echo} basato sull'uso della funzione \func{select}.}
\label{fig:TCP_SelectEchod}
\end{figure}
al valore di \const{FD\_SETSIZE}, ed una variabile \var{max\_fd} per
registrare il valore più alto dei file descriptor aperti.
-Prima di entrare nel ciclo principale (\texttt{\small 6--56}) la nostra
+Prima di entrare nel ciclo principale (\texttt{\small 5--53}) 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
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
+La prima sezione (\texttt{\small 6--8}) 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
+ripetere (\texttt{\small 6}) ogni volta il suo azzeramento per poi procedere
+con il ciclo (\texttt{\small 7--8}) 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
file il file descriptor con il valore più basso disponibile. Questo fa sì che
-si possa eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo,
+si possa eseguire il ciclo (\texttt{\small 7}) a partire da un valore minimo,
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
+aggiornato. Dopo di che basterà controllare (\texttt{\small 8}) 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, si potranno sempre
avere dei \textsl{buchi} nella nostra tabella dato che nelle operazioni i
set} potremo chiamare \func{select} per fargli osservare lo stato degli
stessi (in lettura, presumendo che la scrittura sia sempre consentita). Come
per il precedente esempio di sez.~\ref{sec:TCP_child_hand}, essendo questa
-l'unica funzione che può bloccarsi, ed essere interrotta da un segnale, la
-eseguiremo (\texttt{\small 11--12}) all'interno di un ciclo di \code{while}
+l'unica funzione che può bloccarsi ed essere interrotta da un segnale, la
+eseguiremo (\texttt{\small 9--10}) all'interno di un ciclo di \code{while},
che la ripete indefinitamente qualora esca con un errore di \errcode{EINTR}.
-Nel caso invece di un errore normale si provvede (\texttt{\small 13--16}) ad
-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
-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
-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
-quanto siamo sicuri che \func{accept} non si bloccherà. Per completare la
-trattazione occorre a questo punto aggiungere (\texttt{\small 24}) il nuovo
-file descriptor alla tabella di quelli connessi, ed inoltre, se è il caso,
-aggiornare (\texttt{\small 25}) il valore massimo in \var{max\_fd}.
+Nel caso invece di un errore normale si provvede (\texttt{\small 11--14}) ad
+uscire dal programma stampando un messaggio di errore.
+
+Infine quando la funzione ritorna normalmente avremo in \var{n} il numero di
+socket da controllare. Nello specifico si danno due casi per cui \func{select}
+può ritornare: o si è ricevuta una nuova connessione 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 15--24}): si
+controlla (\texttt{\small 15}) che il socket in ascolto sia fra quelli attivi,
+nel qual caso anzitutto (\texttt{\small 16}) se ne decrementa il numero
+mantenuto nella variabile \var{n}. Poi, inizializzata (\texttt{\small 17}) la
+lunghezza della struttura degli indirizzi, si esegue \func{accept} per
+ottenere il nuovo socket connesso, controllando che non ci siano errori
+(\texttt{\small 18--21}). In questo caso non c'è più la necessità di
+controllare per interruzioni dovute a segnali, in quanto siamo sicuri che
+\func{accept} non si bloccherà. Per completare la trattazione occorre a questo
+punto aggiungere (\texttt{\small 22}) il nuovo file descriptor alla tabella di
+quelli connessi, ed inoltre, se è il caso, aggiornare (\texttt{\small 23}) il
+valore massimo in \var{max\_fd}.
Una volta controllato l'arrivo di nuove connessioni si passa a verificare se
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}.
+(\texttt{\small 26--52}) fintanto che il numero di socket attivi indicato
+dalla variabile \var{n} resta diverso da zero. In questo modo, se l'unico
+socket con attività era quello connesso, avendola opportunamente decrementata
+in precedenza, essa risulterà nulla, pertanto il ciclo di verifica verrà
+saltato e si ritornerà all'inzizio del ciclo principale, ripetendo, dopo
+l'inizializzazione del \textit{file descriptor set} con i nuovi valori nella
+tabella, la chiamata di \func{select}.
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.
+eseguito. Prima di entrare nel ciclo di veridica comunque si inizializza
+(\texttt{\small 25}) 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
+Il primo passo (\texttt{\small 27}) nella verifica è incrementare il valore
dell'indice \var{i} per posizionarsi sul primo valore possibile per un file
descriptor associato ad un eventuale socket connesso, dopo di che si controlla
-(\texttt{\small 31}) se questo è nella tabella dei socket connessi, chiedendo
+(\texttt{\small 28}) se questo è nella tabella dei socket connessi, chiedendo
la ripetizione del ciclo in caso contrario. Altrimenti si passa a verificare
-(\texttt{\small 32}) se il file descriptor corrisponde ad uno di quelli
-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 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
+(\texttt{\small 29}) se il file descriptor corrisponde ad uno di quelli
+attivi, e nel caso si esegue (\texttt{\small 30}) una lettura, uscendo con un
+messaggio in caso di errore (\texttt{\small 31--35}).
+
+Se (\texttt{\small 36}) il numero di byte letti \var{nread} è nullo si è in
+presenza di una \textit{end-of-file}, indice che una connessione che si è
+chiusa, che deve essere trattata (\texttt{\small 36--45}) opportunamente. Il
+primo passo è chiudere (\texttt{\small 37}) anche il proprio capo del socket e
+rimuovere (\texttt{\small 38}) il file descriptor dalla tabella di quelli
+aperti, inoltre occorre verificare (\texttt{\small 39}) 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
+(\texttt{\small 39--43}) il nuovo massimo, altrimenti (\texttt{\small 44}) si
può ripetere il ciclo da capo per esaminare (se ne restano) ulteriori file
descriptor attivi.
file descriptor attivi viene fatta a partire dal valore più basso, questo
significa che siamo anche arrivati alla fine della scansione, per questo
possiamo utilizzare direttamente il valore dell'indice \var{i} con un ciclo
-all'indietro (\texttt{\small 43}) che trova il primo valore per cui la tabella
-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
+all'indietro (\texttt{\small 40}) che trova il primo valore per cui la tabella
+presenta un file descriptor aperto, e lo imposta (\texttt{\small 41}) come
+nuovo massimo, per poi tornare (\texttt{\small 42}) al ciclo principale con un
\code{break}, e rieseguire \func{select}.
Se infine si sono effettivamente letti dei dati dal socket (ultimo caso
-rimasto) si potrà invocare immediatamente (\texttt{\small 49})
+rimasto) si potrà invocare immediatamente (\texttt{\small 46})
\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
+uscire con un messaggio in caso di errore (\texttt{\small 47--50}). Si noti
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
\includecodesample{listati/poll_echod.c}
\end{minipage}
\normalsize
- \caption{La sezione principale del codice della nuova versione di server
- \textit{echo} basati sull'uso della funzione \func{poll}.}
+ \caption{La sezione principale della nuova versione di server
+ \textit{echo} basato sull'uso della funzione \func{poll}.}
\label{fig:TCP_PollEchod}
\end{figure}
Dopo di che si preimposta (\texttt{\small 3}) il valore \var{max\_fd} del file
descriptor aperto con valore più alto a quello del socket in ascolto (al
momento l'unico), e si provvede (\texttt{\small 4--7}) ad inizializzare le
-strutture, disabilitando (\texttt{\small 5}) l'osservazione con un valore
-negativo del campo \var{fd} ma predisponendo (\texttt{\small 6}) il campo
+strutture, disabilitando l'osservazione (\texttt{\small 5}) con un valore
+negativo del campo \var{fd}, ma predisponendo (\texttt{\small 6}) il campo
\var{events} per l'osservazione dei dati normali con \const{POLLRDNORM}.
Infine (\texttt{\small 8}) si attiva l'osservazione del socket in ascolto
inizializzando la corrispondente struttura. Questo metodo comporta, in
socket in ascolto.
Una volta completata l'inizializzazione tutto il lavoro viene svolto
-all'interno del ciclo principale \texttt{\small 10--55}) che ha una struttura
+all'interno del ciclo principale \texttt{\small 9--53}) che ha una struttura
sostanzialmente identica a quello usato per il precedente esempio basato su
-\func{select}. La prima istruzione (\texttt{\small 11--12}) è quella di
-eseguire \func{poll} all'interno di un ciclo che la ripete qualora venisse
-interrotta da un segnale, da cui si esce soltanto quando la funzione ritorna,
-restituendo nella variabile \var{n} il numero di file descriptor trovati
-attivi. Qualora invece si sia ottenuto un errore si procede (\texttt{\small
- 13--16}) alla terminazione immediata del processo provvedendo a stampare una
-descrizione dello stesso.
+\func{select}. La prima istruzione (\texttt{\small 10}) è quella di eseguire
+\func{poll} all'interno di un ciclo che la ripete qualora venisse interrotta
+da un segnale, da cui si esce soltanto quando la funzione ritorna restituendo
+nella variabile \var{n} il numero di file descriptor trovati attivi. Qualora
+invece si sia ottenuto un errore si procede (\texttt{\small 11--14}) alla
+terminazione immediata del processo provvedendo a stampare una descrizione
+dello stesso.
Una volta ottenuta dell'attività su un file descriptor si hanno di nuovo due
-possibilità. La prima possibilità è che ci sia attività sul socket in ascolto,
-indice di una nuova connessione, nel qual caso si controlla (\texttt{\small
- 17}) se il campo \var{revents} della relativa struttura è attivo; se è così
-si provvede (\texttt{\small 18}) a decrementare la variabile \var{n} (che
-assume il significato di numero di file descriptor attivi rimasti da
-controllare) per poi (\texttt{\small 19--23}) effettuare la chiamata ad
-\func{accept}, terminando il processo in caso di errore. Se la chiamata ad
-\func{accept} ha successo si procede attivando (\texttt{\small 24}) la
-struttura relativa al nuovo file descriptor da essa ottenuto, modificando
-(\texttt{\small 24}) infine quando necessario il valore massimo dei file
-descriptor aperti mantenuto in \var{max\_fd}.
+possibilità. La prima è che ci sia attività sul socket in ascolto, indice di
+una nuova connessione, nel qual caso si controlla (\texttt{\small 17}) se il
+campo \var{revents} della relativa struttura è attivo; se è così si provvede
+(\texttt{\small 16}) a decrementare la variabile \var{n} (che assume il
+significato di numero di file descriptor attivi rimasti da controllare) per
+poi (\texttt{\small 17--21}) effettuare la chiamata ad \func{accept},
+terminando il processo in caso di errore. Se la chiamata ad \func{accept} ha
+successo si procede attivando (\texttt{\small 22}) la struttura relativa al
+nuovo file descriptor da essa ottenuto, modificando (\texttt{\small 23})
+infine quando necessario il valore massimo dei file descriptor aperti
+mantenuto in \var{max\_fd}.
La seconda possibilità è che vi sia dell'attività su uno dei socket aperti in
-precedenza, nel qual caso si inizializza (\texttt{\small 27}) l'indice \var{i}
+precedenza, nel qual caso si inizializza (\texttt{\small 25}) l'indice \var{i}
del vettore delle strutture \struct{pollfd} al valore del socket in ascolto,
dato che gli ulteriori socket aperti avranno comunque un valore superiore. Il
-ciclo (\texttt{\small 28--54}) prosegue fintanto che il numero di file
+ciclo (\texttt{\small 26--52}) prosegue fintanto che il numero di file
descriptor attivi, mantenuto nella variabile \var{n}, è diverso da zero. Se
pertanto ci sono ancora socket attivi da individuare si comincia con
-l'incrementare (\texttt{\small 30}) l'indice e controllare (\texttt{\small
- 31}) se corrisponde ad un file descriptor in uso analizzando il valore del
+l'incrementare (\texttt{\small 27}) l'indice e controllare (\texttt{\small
+ 28}) se corrisponde ad un file descriptor in uso analizzando il valore del
campo \var{fd} della relativa struttura e chiudendo immediatamente il ciclo
qualora non lo sia. Se invece il file descriptor è in uso si verifica
-(\texttt{\small 31}) se c'è stata attività controllando il campo
-\var{revents}.
+(\texttt{\small 29}) se c'è stata attività controllando il campo
+\var{revents}.
Di nuovo se non si verifica la presenza di attività il ciclo si chiude subito,
-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
+altrimenti si provvederà (\texttt{\small 30}) a decrementare il numero \var{n}
+di file descriptor attivi da controllare e ad eseguire (\texttt{\small 31}) la
+lettura, ed in caso di errore (\texttt{\small 32--35}) al solito lo si
notificherà uscendo immediatamente. Qualora invece si ottenga una condizione
-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
-valore di \var{max\_fd}. L'ultimo passo è (\texttt{\small 46}) chiudere il
+di \textit{end-of-file} (\texttt{\small 36--45}) si provvederà a chiudere
+(\texttt{\small 37}) anche il nostro capo del socket e a marcarlo
+(\texttt{\small 38}) come inutilizzato nella struttura ad esso associata.
+Infine dovrà essere ricalcolato (\texttt{\small 39--43}) un eventuale nuovo
+valore di \var{max\_fd}. L'ultimo passo è chiudere (\texttt{\small 44}) il
ciclo in quanto in questo caso non c'è più niente da riscrivere all'indietro
sul socket.
-Se invece si sono letti dei dati si provvede (\texttt{\small 48}) ad
+Se invece si sono letti dei dati si provvede (\texttt{\small 46}) ad
effettuarne la riscrittura all'indietro, con il solito controllo ed eventuale
-uscita e notifica in caso di errore (\texttt{\small 49--52}).
+uscita e notifica in caso di errore (\texttt{\small 47--51}).
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};
considerazioni finali di sez.~\ref{sec:TCP_serv_select}.
-\subsection{\textit{I/O multiplexing} con \textit{epoll}}
-\label{sec:TCP_serv_epoll}
+%\subsection{\textit{I/O multiplexing} con \textit{epoll}}
+%\label{sec:TCP_serv_epoll}
-Da fare.
+%Da fare.
% TODO fare esempio con epoll