From: Simone Piccardi Date: Sun, 7 Nov 2004 23:19:20 +0000 (+0000) Subject: Iniziata trattazione di getaddrinfo, aggiunte figure e definizione di X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=a3e1645556c933f9c430c507db629e31027c4dd9 Iniziata trattazione di getaddrinfo, aggiunte figure e definizione di addrinfo, modificato il Makefile per produrre il PDF dall'EPS diretto. --- diff --git a/Makefile b/Makefile index a3f6a9f..ce650d6 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ $(HTML_C): %.c.html: %.c $(HTML_H): %.h.html: %.h source-highlight -f html -s cpp $< -$(PDF_IMG): %.pdf: %.ps +$(PDF_IMG): %.pdf: %.eps epstopdf $< --outfile=$@ $(PS_IMG): %.ps : %.eps diff --git a/img/addrinfo_list.dia b/img/addrinfo_list.dia new file mode 100644 index 0000000..a399fb2 Binary files /dev/null and b/img/addrinfo_list.dia differ diff --git a/listati/addrinfo.h b/listati/addrinfo.h new file mode 100644 index 0000000..7bd9408 --- /dev/null +++ b/listati/addrinfo.h @@ -0,0 +1,11 @@ +struct addrinfo +{ + int ai_flags; /* Input flags. */ + int ai_family; /* Protocol family for socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol for socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address for socket. */ + char *ai_canonname; /* Canonical name for service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; diff --git a/sockctrl.tex b/sockctrl.tex index dbe5af3..a6eabcd 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1204,11 +1204,11 @@ funzioni \func{gethostbyaddr}, \func{gethostbyname}, \var{getipnodebyname} e \var{getipnodebyaddr} ed è stata introdotta una interfaccia completamente nuova. -La prima funzione di questa interfaccia, che combina le funzionalità di -\func{getipnodebyname}, \func{getipnodebyaddr}, \func{getservbyname} e -\func{getservbyport}, consentendo di ottenere contemporaneamente la -risoluzione di un indirizzo e di un servizio, è \funcd{getaddrinfo}, il cui -prototipo è: +La prima funzione di questa interfaccia è \funcd{getaddrinfo}, che combina le +funzionalità delle precedenti \func{getipnodebyname}, \func{getipnodebyaddr}, +\func{getservbyname} e \func{getservbyport}, consentendo di ottenere +contemporaneamente sia la risoluzione di un indirizzo simbolico che del nome +un servizio; il suo prototipo è: \begin{functions} \headdecl{netdb.h} \headdecl{sys/socket.h} @@ -1224,12 +1224,239 @@ prototipo \end{functions} La funzione prende come primo argomento il nome della macchina che si vuole -risolvere. Questo, oltre ad un comune nome a dominio, può essere anche un -indirizzo numerico in forma \textit{dotted-decimal} per IPv4 o in formato -esadecimale per IPv6. Si può anche specificare il nome di una rete invece che -di una singola macchina. Il secondo argomento specifica invece il nome del -servizio che si intende risolvere. Uno di questi due argomenti può essere -anche inizializzato a \const{NULL} +risolvere, specificato tramite la stringa \param{node}. Questo argomento, +oltre ad un comune nome a dominio, può indicare anche un indirizzo numerico in +forma \textit{dotted-decimal} per IPv4 o in formato esadecimale per IPv6. Si +può anche specificare il nome di una rete invece che di una singola macchina. +Il secondo argomento, \param{service}, specifica invece il nome del servizio +che si intende risolvere. Per uno dei due argomenti si può anche usare il +valore \const{NULL}, nel qual caso la risoluzione verrà effettuata utilizzando +soltantoo sulla base del valore dell'altro. + +Il terzo argomento, \param{hints}, deve essere invece un puntatore ad una +struttura \struct{addrinfo} usata per dare dei \textsl{suggerimenti} al +procedimento di risoluzione riguardo al protocollo o del tipo di socket che si +intenderà utilizzare; la funzione infatti permette di effettuare ricerche +generiche sugli indirizzi, usando sia IPv4 che IPv6, e richiedere risoluzioni +sui nomi dei servizi indipendentemente dal protocollo (ad esempio TCP o UDP) +che questi possono utilizzare. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includestruct{listati/addrinfo.h} + \end{minipage} + \caption{La struttura \structd{addrinfo} usata nella nuova interfaccia POSIX + per la risoluzione di nomi a dominio e servizi.} + \label{fig:sock_addrinfo_struct} +\end{figure} + +La struttura \struct{addrinfo}, la cui definizione\footnote{la definizione è + ripresa direttamente dal file \texttt{netdb.h} in questa struttura viene + dichiarata, la pagina di manuale riporta \type{size\_t} come tipo di dato + per il campo \var{ai\_addrlen}, qui viene usata quanto previsto dallo + standard POSIX, in cui viene utilizzato \type{socklen\_t}; i due tipi di + dati sono comunque equivalenti.} è riportata in +fig.~\ref{fig:sock_addrinfo_struct} viene usata sia in ingresso, per passare +dei valori di controllo alla funzione, che in uscita, per ricevere i +risultati. Il primo campo, \var{ai\_flags}, è una maschera binaria di bit che +permettono di controllare le varie modalità di risoluzione degli indirizzi, +che viene usato soltanto in ingresso. I tre campi successivi \var{ai\_family}, +\var{ai\_socktype}, e \var{ai\_protocol} contengono rispettivamente la +famiglia di indirizzi, il tipo di socket e il protocollo, in ingresso vengono +usati per impostare una selezione (impostandone il valore nella struttura +puntata da \param{hints}), mentre in uscita indicano il tipo di risultato +contenuto nella struttura. + +Tutti i campi seguenti vengono usati soltanto in uscita; il campo +\var{ai\_addrlen} indica la dimensione della struttura degli indirizzi +ottenuta come risultato, il cui contenuto sarà memorizzato nella struttura +\struct{sockaddr} posta all'indirizzo puntato dal campo \var{ai\_addr}. Il +campo \var{ai\_canonname} è il puntatore alla stringa contenente il nome +canonico della macchina, ed infine, quando la funzione restituisce più di un +risultato, \var{ai\_next} è il puntatore alla struttura \struct{addrinfo} +successiva della lista. + +Ovviamente non è necessario dare dei suggerimenti in ingresso, ed usando +\const{NULL} come valore per l'argomento \param{hints} si possono compiere +ricerche generiche. Se però si specifica un valore non nullo questo deve +puntare ad una struttura \struct{addrinfo} precedentemente allocata nella +quale siano stati opportunamente impostati i valori dei campi +\var{ai\_family}, \var{ai\_socktype}, \var{ai\_protocol} ed \var{ai\_flags}. + +I due campi \var{ai\_family} e \var{ai\_socktype} prendono gli stessi valori +degli analoghi argomenti della funzione \func{socket}; in particolare per +\var{ai\_family} si possono usare i valori di tab.~\ref{tab:net_pf_names} ma +sono presi in considerazione solo \const{PF\_INET} e \const{PF\_INET6}, mentre +se non si vuole specificare questo nessuna famiglia di indirizzi si può usare +il valore \const{PF\_UNSPEC}. Allo stesso modo per \var{ai\_socktype} si +possono usare i valori illustrati sez.~\ref{sec:sock_type} per indicare per +quale tipo di socket si vuole risolvere il servizio indicato, anche se i soli +significativi sono \const{SOCK\_STREAM} e \const{SOCK\_DGRAM}; in questo caso, +se non si vuole effettuare nessuna risoluzione specifica, si potrà usare un +valore nullo. + +Il campo \var{ai\_protocol} permette invece di effettuare la selezione dei +risultati per il nome del servizio usando il numero identificativo del +rispettivo protocollo di trasporto (i cui valori possibili sono riportati in +\file{/etc/protocols}); di nuovo i due soli valori utilizzabili sono quelli +relativi a UDP e TCP, o il valore nullo che indica di ignorare questo campo +nella selezione. + +Infine l'ultimo campo è \var{ai\_flags}; che deve essere impostato come una +maschera binaria; i bit di questa variabile infatti vengono usati per dare +delle indicazioni sul tipo di risoluzione voluta, ed hanno valori analoghi a +quelli visti in sez.~\ref{sec:sock_name_services} per \func{getipnodebyname}; +il valore di \var{ai\_flags} può essere impostata con un OR aritmetico delle +costanti di tab.~\ref{tab:ai_flags_values}, ciascuna delle quali identifica un +bit della maschera. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{AI\_PASSIVE} & viene utilizzato per ottenere un indirizzo in + formato adatto per una successiva chiamata a + \func{bind}. Se specificato quando si è usato + \const{NULL} come valore per \param{node} gli + indirizzi restituiti saranno inizializzati al + valore generico (\const{INADDR\_ANY} per IPv4 e + \const{IN6ADDR\_ANY\_INIT} per IPv6), altrimenti + verrà usato l'indirizzo dell'interfaccia di + \textit{loopback}. Se invece non è impostato gli + indirizzi verrano restituiti in formato adatto ad + una chiamata a \func{connect} o \func{sendto}.\\ + \const{AI\_CANONNAME} & richiede la restituzione del nome canonico della + macchina, che verrà salvato in una stringa il cui + indirizzo sarà restituito nel campo + \var{ai\_canonname} della prima struttura + \struct{addrinfo} dei risultati. Se il nome + canonico non è disponibile al suo posto + viene restituita una copia di \param{node}. \\ + \const{AI\_NUMERICHOST}& se impostato il nome della macchina specificato + con \param{node} deve essere espresso in forma + numerica, altrimenti sarà restituito un errore + \const{EAI\_NONAME} (vedi + tab.~\ref{tab:addrinfo_error_code}), in questo + modo si evita ogni chiamata alle funzioni di + risoluzione.\\ + \const{AI\_V4MAPPED} & stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \const{AI\_ALL} & stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \const{AI\_ADDRCONFIG} & stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \hline + \end{tabular} + \caption{Costanti associate ai bit del campo \var{ai\_flags} della struttura + \struct{addrinfo}.} + \label{tab:ai_flags_values} +\end{table} + +Come ultimo argomento di \func{getaddrinfo} deve essere passato un puntatore +ad una variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che +verrà utilizzata dalla funzione per restituire (come \textit{value result + argument}) i propri risultati. La funzione infatti è rientrante, ed alloca +autonomamente tutta la memoria necessaria in cui verranno riportati i +risultati della risoluzione. La funzione restituisce in \param{res} il +puntatore alla prima di una \textit{linked list} di strutture di tipo +\struct{addrinfo} contenenti tutte le informazioni ottenute. + +La funzione restituisce un valore nullo in caso di successo, o un codice in +caso di errore. I valori usati come codice di errore sono riportati in +tab.~\ref{tab:addrinfo_error_code}; dato che la funzione utilizza altre +funzioni e chiamate al sistema per ottenere il suo risultato in generale il +valore di \var{errno} non è significativo, eccetto il caso in cui si sia +ricevuto un errore di \const{EAI\_SYSTEM}, nel qual caso l'errore +corrispondente è riportato tramite \var{errno}. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{EAI\_FAMILY} & la famiglia di indirizzi richiesta non è + supportata. \\ + \const{EAI\_SOCKTYPE}& il tipo di socket richiesto non è supportato. \\ + \const{EAI\_BADFLAGS}& il campo \var{ai\_flags} contiene dei valori non + validi. \\ + \const{EAI\_NONAME} & il nome a dominio o il servizio non sono noti, + viene usato questo errore anche quando si specifica + il valore \const{NULL} per entrambi gli argomenti + \param{node} e \param{service}. \\ + \const{EAI\_SERVICE} & il servizio richiesto non è disponibile per il tipo + di socket richiesto, anche se può esistere per + altri tipi di socket. \\ + \const{EAI\_ADDRFAMILY}& la rete richiesta non ha nessun indirizzo di rete + per la famiglia di indirizzi specificata. \\ + \const{EAI\_NODATA} & la . \\ + \const{EAI\_MEMORY} & è stato impossibile allocare la memoria necessaria + alle operazioni. \\ + \const{EAI\_FAIL} & il DNS ha restituito un errore di risoluzione + permanente. \\ + \const{EAI\_AGAIN} & il DNS ha restituito un errore di risoluzione + temporaneo, si può ritentare in seguito. \\ + \const{EAI\_SYSTEM} & c'è stato un errore di sistema, si può controllare + \var{errno} per i dettagli. \\ +% \hline +% estensioni GNU, trovarne la documentazione +% \const{EAI\_INPROGRESS}& richiesta in corso. \\ +% \const{EAI\_CANCELED}& la richiesta è stata cancellata.\\ +% \const{EAI\_NOTCANCELED}& la richiesta non è stata cancellata. \\ +% \const{EAI\_ALLDONE} & tutte le richieste sono complete. \\ +% \const{EAI\_INTR} & richiesta interrotta. \\ + \hline + \end{tabular} + \caption{Costanti associate ai valori dei codici di errore della funzione + \func{getaddrinfo}.} + \label{tab:addrinfo_error_code} +\end{table} + + +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}. + +\begin{figure}[!htb] + \centering + \includegraphics[width=10cm]{img/addrinfo_list} + \caption{La \textit{linked list} delle strutture \struct{addrinfo} + restituite da \func{getaddrinfo}.} + \label{fig:sock_addrinfo_list} +\end{figure} + + +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 è: +\begin{functions} + \headdecl{netdb.h} + + \funcdecl{void freeaddrinfo(struct addrinfo *res)} + + Libera la memoria allocata da una precedente chiamata a \func{getaddrinfo}. + + \bodydesc{La funzione non restituisce nessun codice di errore.} +\end{functions} + +La funzione prende come unico argomento il puntatore \param{res}, ottenuto da +una precedente chiamata a \func{getaddrinfo}, e scandisce la lista delle +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}. + diff --git a/socket.tex b/socket.tex index 968a18c..9d86a3e 100644 --- a/socket.tex +++ b/socket.tex @@ -228,7 +228,7 @@ valori numerici.\footnote{in Linux, come si pu lo stesso nome.} I domini (e i relativi nomi simbolici), così come i nomi delle famiglie di -indirizzi, sono definiti dall'header \textit{socket.h}. Un elenco delle +indirizzi, sono definiti dall'header \texttt{socket.h}. Un elenco delle famiglie di protocolli disponibili in Linux è riportato in tab.~\ref{tab:net_pf_names}.\footnote{l'elenco indica tutti i protocolli definiti; fra questi però saranno utilizzabili solo quelli per i quali si è