Completata la parte su getaddrinfo e rifatto il programma di esempio per
[gapil.git] / sockctrl.tex
index a6eabcd8cbecd2a044d681b8967645505480269d..b86644240d8b0e78ae0ef923b354617fec6114f1 100644 (file)
@@ -705,20 +705,20 @@ suoi risultati.
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \includecodesample{listati/myhost.c}
+    \includecodesample{listati/mygethost.c}
   \end{minipage}
   \normalsize
   \caption{Esempio di codice per la risoluzione di un indirizzo.}
-  \label{fig:myhost_example}
+  \label{fig:mygethost_example}
 \end{figure}
 
 Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in
-fig.~\ref{fig:myhost_example} è riportato un estratto del codice di un
+fig.~\ref{fig:mygethost_example} è riportato un estratto del codice di un
 programma che esegue una semplice interrogazione al \textit{resolver} usando
 \func{gethostbyname} e poi ne stampa a video i risultati. Al solito il
 sorgente completo, che comprende il trattamento delle opzioni ed una funzione
-per stampare un messaggio di aiuto, è nel file \texttt{myhost.c} dei sorgenti
-allegati alla guida.
+per stampare un messaggio di aiuto, è nel file \texttt{mygethost.c} dei
+sorgenti allegati alla guida.
 
 Il programma richiede un solo argomento che specifichi il nome da cercare,
 senza il quale (\texttt{\small 12--15}) esce con un errore. Dopo di che
@@ -1419,14 +1419,36 @@ corrispondente 
   \label{tab:addrinfo_error_code}
 \end{table}
 
+Come per i codici di errore di \func{gethostbyname} anche in questo caso è
+fornita una apposita funzione, analoga di \func{strerror}, che consente di
+utilizzarli direttamente per stampare a video un messaggio esplicativo; la
+funzione è \func{gai\_strerror} ed il suo prototipo è:
+\begin{functions}
+  \headdecl{netdb.h} 
+
+  \funcdecl{const char *gai\_strerror(int errcode)}
+
+  Fornisce il messaggio corrispondente ad un errore di \func{getaddrinfo}.
 
-Dato che più di un indirizzo possono corrispondere ad un certo nome a dominio,
-e più di un servizio possono essere associati ad un certo nome (in genere su
-due protocolli diversi) è assolutamente normale ricevere come risposta una
-lista di più strutture \struct{addrinfo}, a meno di non avere usato una
-selezione specifica. Ad esempio se si richiede la risoluzione del servizio
-\textit{echo} si avrà come risposta la lista illustrata in
-fig.~\ref{fig:sock_addrinfo_list}.
+  \bodydesc{La funzione restituisce il puntatore alla stringa contenente il
+    messaggio di errore.}
+\end{functions}
+
+La funzione restituisce un puntatore alla stringa contenente il messaggio
+corrispondente dal codice di errore \param{errcode} ottenuto come valore di
+ritorno di \func{getaddrinfo}.  La stringa è allocata staticamente, ma essendo
+costante, ed accessibile in sola lettura, questo non comporta nessun problema
+di rientranza della funzione.
+
+Dato che ad un certo nome a dominio possono corrispondere più indirizzi IP
+(sia IPv4 che IPv6), e che un certo servizio può essere fornito su protocolli
+e tipi di socket diversi, in generale, a meno di non aver eseguito una
+selezione specifica attraverso l'uso di \param{hints}, si otterrà una diversa
+struttura \struct{addrinfo} per ciascuna possibilità.  Ad esempio se si
+richiede la risoluzione del servizio \textit{echo} per l'indirizzo
+\texttt{www.truelite.it}, e si imposta \const{AI\_CANONNAME} per avere anche
+la risoluzione del nome canonico, si avrà come risposta della funzione la
+lista illustrata in fig.~\ref{fig:sock_addrinfo_list}.
 
 \begin{figure}[!htb]
   \centering
@@ -1436,11 +1458,102 @@ fig.~\ref{fig:sock_addrinfo_list}.
   \label{fig:sock_addrinfo_list}
 \end{figure}
 
+Come primo esempio di uso di \func{getaddrinfo} vediamo un programma
+elementare di interrogazione del resolver basato questa funzione, il cui corpo
+principale è riportato in fig.~\ref{fig:mygetaddr_example}. Il codice completo
+del programma, compresa la gestione delle opzioni in cui è gestita l'eventuale
+inizializzazione dell'argomento \var{hints} per restringere le ricerche su
+protocolli, tipi di socket o famiglie di indirizzi, è disponibile nel file
+\texttt{mygetaddr.c} dei sorgenti allegati alla guida.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/mygetaddr.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice per la risoluzione di un indirizzo.}
+  \label{fig:mygetaddr_example}
+\end{figure}
+
+Il corpo principale inizia controllando (\texttt{\small 1--5}) il numero di
+argomenti passati, che devono essere sempre due, e corrispondere
+rispettivamente all'indirizzo ed al nome del servizio da risolvere. A questo
+segue la chiamata (\texttt{\small 7}) alla funzione \func{getaddrinfo}, ed il
+successivo controllo (\texttt{\small 8--11}) del suo corretto funzionamento,
+senza il quale si esce immediatamente stampando il relativo codice di errore.
+
+Se la funzione ha restituito un valore nullo il programma prosegue
+inizializzando (\texttt{\small 12}) il puntatore \var{ptr} che sarà usato nel
+sucessivo ciclo (\texttt{\small 14--35}) di scansione della lista delle
+strutture \struct{addrinfo} restituite dalla funzione. Prima di eseguire
+questa scansione (\texttt{\small 12}) viene stampato il valore del nome
+canonico che è presente solo nella prima struttura.
+
+La scansione viene ripetuta (\texttt{\small 14}) fintanto che si ha un
+puntatore valido. La selezione principale è fatta sul campo \var{ai\_family},
+che stabilisce a quale famiglia di indirizzi fa riferimento la struttura in
+esame. Le possibilità sono due, un indirizzo IPv4 (\texttt{\small 15}) o IPv6
+(\texttt{\small 21}), se nessuna delle due si verifica si provvede
+(\texttt{\small 27--30}) a stampare un messaggio di errore ed
+uscire.\footnote{questa eventualità non dovrebbe mai verificarsi, almeno
+  fintanto che la funzione \func{getaddrinfo} lavora correttamente.}
+
+Per ciascuno delle due possibili famiglie di indirizzi si estraggono le
+informazioni che poi verranno stampate alla fine del ciclo (\texttt{\small
+  31--34}). Il primo caso esaminato (\texttt{\small 15--21}) è quello degli
+indirizzi IPv4, nel qual caso prima se ne stampa l'indentificazione
+(\texttt{\small 16}) poi si provvede a ricavare la struttura degli indirizzi
+(\texttt{\small 17}) indirizzata dal campo \var{ai\_addr}, eseguendo un
+opportuno casting del puntatore per poter estrarre da questa la porta
+(\texttt{\small 18}) e poi l'indirizzo (\texttt{\small 19}) che verrà
+convertito con una chiamata ad \func{inet\_ntop}.
+
+La stessa operazione (\texttt{\small 21--27}) viene ripetuta per gli indirizzi
+IPv6, usando la rispettiva struttura degli indirizzi. Si noti anche come in
+entrambi i casi per la chiamata a \func{inet\_ntop} si sia dovuto passare il
+puntatore al campo contenente l'indirizzo IP nella struttura puntata dal campo
+\var{ai\_addr}.\footnote{il meccanismo è complesso a causa del fatto che al
+  contrario di IPv4, in cui l'indirizzo IP può essere espresso con un semplice
+  numero intero, in IPv6 questo deve essere necessariamente fornito come
+  struttura, e pertanto anche se nella struttura puntata da \var{ai\_addr}
+  sono presenti direttamente i valori finali, per l'uso con \func{inet\_ntop}
+  occorre comunque passare un puntatore agli stessi (ed il costrutto
+  \code{\&addr6->sin6\_addr} è corretto in quanto l'operatore \texttt{->} ha
+  on questo caso precedenza su \texttt{\&}).}
+
+Una volta estratte dalla struttura \struct{addrinfo} tutte le informazioni
+relative alla risoluzione richiesta e stampati i relativi valori, l'ultimo
+passo è (\texttt{\small 34}) estrarre da \var{ai\_next} l'indirizzo della
+eventuale successiva struttura presente nella lista e ripetere il ciclo, fin
+tanto che, completata la scansione, questo avrà un valore nullo e si potrà
+terminare (\texttt{\small 36}) il programma.
+
+Si tenga presente che \func{getaddrinfo} non garantisce nessun particolare
+ordinamento della lista delle strutture \struct{addrinfo} restituite, anche se
+usualmente i vari indirizzi IP (se ne è presente più di uno) sono forniti
+nello stesso ordine in cui vengono inviati dal server DNS. In particolare
+nulla garantisce che vengano forniti prima i dati relativi ai servizi di un
+determinato protocollo o tipo di socket, se ne sono presenti di diversi.  Se
+allora utilizziamo il nostro programma potremo verificare il risultato:
+\begin{verbatim}
+[piccardi@gont sources]$ ./mygetaddr -c  gapil.truelite.it echo
+Canonical name sources2.truelite.it
+IPv4 address:
+        Indirizzo 62.48.34.25
+        Protocollo 6
+        Porta 7
+IPv4 address:
+        Indirizzo 62.48.34.25
+        Protocollo 17
+        Porta 7
+\end{verbatim}
+%$
 
 Una volta estratti i risultati dalla \textit{linked list} puntata da
-\param{res} si dovrà avere cura di disallocare opportunamente tutta la
-memoria, per questo viene fornita l'apposita funzione \funcd{freeaddrinfo}, il
-cui prototipo è:
+\param{res} se questa non viene più utilizzata si dovrà avere cura di
+disallocare opportunamente tutta la memoria, per questo viene fornita
+l'apposita funzione \funcd{freeaddrinfo}, il cui prototipo è:
 \begin{functions}
   \headdecl{netdb.h} 
 
@@ -1457,7 +1570,12 @@ strutture per liberare tutta la memoria allocata. Dato che la funzione non ha
 valori di ritorno deve essere posta molta cura nel passare un valore valido
 per \param{res}.
 
-
+Si tenga presente infine che se si copiano i risultati da una delle strutture
+\struct{addrinfo} restituite nella lista indicizzata da \param{res}, occorre
+avere cura di eseguire una \index{\textit{deep~copy}}\textit{deep copy} in cui
+si copiano anche tutti i dati presenti agli indirizzi contenuti nella
+struttura \struct{addrinfo}, perché una volta disallocati i dati con
+\func{freeaddrinfo} questi non sarebbero più disponibili. 
 
 
 \section{Le opzioni dei socket}