X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=sockctrl.tex;h=b86644240d8b0e78ae0ef923b354617fec6114f1;hp=a6eabcd8cbecd2a044d681b8967645505480269d;hb=839d84a7794ebbde7edafb5b0f30fc3455b26f7b;hpb=a3e1645556c933f9c430c507db629e31027c4dd9 diff --git a/sockctrl.tex b/sockctrl.tex index a6eabcd..b866442 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -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}