From 839d84a7794ebbde7edafb5b0f30fc3455b26f7b Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 13 Nov 2004 15:16:13 +0000 Subject: [PATCH] Completata la parte su getaddrinfo e rifatto il programma di esempio per consentire l'impostazione della ricerca per protocolli, tipi di socket e famiglie di indirizzi --- img/addrinfo_list.dia | Bin 3499 -> 3518 bytes listati/mygetaddr.c | 47 ++++++------------ sockctrl.tex | 103 ++++++++++++++++++++++++++++++++++---- sources/mygetaddr.c | 113 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 197 insertions(+), 66 deletions(-) diff --git a/img/addrinfo_list.dia b/img/addrinfo_list.dia index fca8a26f1f9cda90d76fba754e0aaa10df0d7404..fa5937ffb82480293132a425230d0bf37b0bf8d2 100644 GIT binary patch literal 3518 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 Z@%B~yi}^P#;_J7s{s$cwuE7O70RRv*uSfs@ diff --git a/listati/mygetaddr.c b/listati/mygetaddr.c index 1499e2b..2332b13 100644 --- a/listati/mygetaddr.c +++ b/listati/mygetaddr.c @@ -1,56 +1,37 @@ - struct addrinfo hint; - struct addrinfo *res, *ptr; - int ret, port; - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - char buffer[INET6_ADDRSTRLEN]; - char *string; - ... + /* remaining argument check */ if ((argc - optind) != 2) { printf("Wrong number of arguments %d\n", argc - optind); usage(); } -/* main body */ - ret = getaddrinfo(argv[1], argv[2], NULL, &res); + /* main body */ + ret = getaddrinfo(argv[optind], argv[optind+1], &hint, &res); if (ret != 0) { printf("Resolution error %s\n", gai_strerror(ret)); exit(1); } - ptr = res; - printf("Canonical name %s\n", ptr->ai_canonname); - do { - if (ptr->ai_family == PF_INET) { + ptr = res; /* init list pointer */ + printf("Canonical name %s\n", ptr->ai_canonname); /* print cname */ + while (ptr != NULL) { /* loop on list */ + if (ptr->ai_family == PF_INET) { /* if IPv4 */ printf("IPv4 address: \n"); - addr = (struct sockaddr_in *) ptr->ai_addr; - port = ntohs(addr->sin_port); + addr = (struct sockaddr_in *) ptr->ai_addr; /* address */ + port = ntohs(addr->sin_port); /* port */ string = inet_ntop(addr->sin_family, &addr->sin_addr, buffer, sizeof(buffer)); - } else if (ptr->ai_family == PF_INET6) { + } else if (ptr->ai_family == PF_INET6) { /* if IPv6 */ printf("IPv6 address: \n"); - addr6 = (struct sockaddr_in *) ptr->ai_addr; - port = ntohs(addr6->sin6_port); + addr6 = (struct sockaddr_in *) ptr->ai_addr; /* address */ + port = ntohs(addr6->sin6_port); /* port */ string = inet_ntop(addr6->sin6_family, &addr6->sin6_addr, buffer, sizeof(buffer)); - } else { + } else { /* else is an error */ printf("Address family error\n"); exit(1); } printf("\tIndirizzo %s\n", string); printf("\tProtocollo %i\n", ptr->ai_protocol); printf("\tPorta %i\n", port); - - ptr = ptr->ai_next; - } while (ptr != NULL); + } exit(0); } -/* - * routine to print usage info and exit - */ -void usage(void) { - printf("Program mygethost: do an hostname resolution \n"); - printf("Usage:\n"); - printf(" mygethost [-h] hostname service\n"); - printf(" -h print this help\n"); - exit(1); -} diff --git a/sockctrl.tex b/sockctrl.tex index 8f6e634..b866442 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1445,7 +1445,9 @@ Dato che ad un certo nome a dominio possono corrispondere pi 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} si avrà come risposta la +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] @@ -1457,10 +1459,12 @@ lista illustrata in fig.~\ref{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.. Il codice -del programma è nel file \texttt{mygetaddr.c}, dei sorgenti allegati alla -guida. +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 @@ -1469,15 +1473,87 @@ guida. \end{minipage} \normalsize \caption{Esempio di codice per la risoluzione di un indirizzo.} - \label{fig:mygethost_example} + \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} @@ -1494,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} diff --git a/sources/mygetaddr.c b/sources/mygetaddr.c index aa83006..ca01d74 100644 --- a/sources/mygetaddr.c +++ b/sources/mygetaddr.c @@ -26,6 +26,7 @@ * *****************************************************************************/ #include +#include #include #include #include /* C standard library */ @@ -49,28 +50,84 @@ int main(int argc, char *argv[]) /* * Variables definition */ - int i; + int i,j; struct addrinfo hint; struct addrinfo *res, *ptr; int ret, port; struct sockaddr_in *addr; struct sockaddr_in6 *addr6; - char buffer[INET6_ADDRSTRLEN]; char *string; + char buffer[INET6_ADDRSTRLEN]; + char *protocols[] = { "tcp","udp", NULL }; + int protval[] = { 6, 17 }; + char *socktype[] = { "dgram","stream", NULL }; + int sockval[] = { SOCK_DGRAM, SOCK_STREAM }; + int debug = 0; + /* + * Init variables + */ + memset(&hint, 0, sizeof(hint)); + hint.ai_family = PF_UNSPEC; /* * Input section: decode command line parameters * Use getopt function */ opterr = 0; /* don't want writing to stderr */ - while ( (i = getopt(argc, argv, "h")) != -1) { + while ( (i = getopt(argc, argv, "hdcp:t:v:")) != -1) { switch (i) { /* * Handling options */ - case 'h': /* help option */ + case 'h': /* help option */ printf("Wrong -h option use\n"); usage(); - return -1; + break; + case 'c': /* set canonical host name resolution */ + hint.ai_flags = hint.ai_flags | AI_CANONNAME; + break; + case 'd': /* set canonical host name resolution */ + debug = 1; + break; + case 'p': /* set protocol value */ + j = 0; + while ( (string = protocols[j]) != NULL ) { + if ( (strncmp(string, optarg, strlen(string)) == 0) ) { + hint.ai_protocol = protval[j]; + break; + } + j++; + } + if (j>=2) { + printf("Wrong protocol, use 'tcp' or 'udp'\n\n"); + usage(); + } + break; + case 't': /* set socket type value */ + j = 0; + while ( (string = socktype[j]) != NULL ) { + if ( (strncmp(string, optarg, strlen(string)) == 0) ) { + hint.ai_socktype = sockval[j]; + break; + } + j++; + } + if (j>=2) { + printf("Wrong socket type, use 'dgram' or 'stream'\n\n"); + usage(); + } + break; + case 'v': /* set address type */ + j = strtol(optarg, NULL, 10); + if (j == 4) { + hint.ai_family = PF_INET; + break; + } + if (j == 6) { + hint.ai_family = PF_INET6; + break; + } + printf("Wrong IP protocol version, use 4 o 6\n\n"); + usage(); break; case '?': /* unrecognized options */ printf("Unrecognized options -%c\n",optopt); @@ -86,42 +143,50 @@ int main(int argc, char *argv[]) * Main code beginning * * ***********************************************************/ + /* if debug actived printout hint values*/ + if (debug) { + printf("hint.ai_flag = %d\n", hint.ai_flags); + printf("hint.ai_family = %d\n", hint.ai_family); + printf("hint.ai_socktype = %d\n", hint.ai_socktype); + printf("hint.ai_protocol = %d\n", hint.ai_protocol); + printf("address = %s\n", argv[optind]); + printf("port = %s\n", argv[optind+1]); + } + /* remaining argument check */ if ((argc - optind) != 2) { printf("Wrong number of arguments %d\n", argc - optind); usage(); } - - ret = getaddrinfo(argv[1], argv[2], NULL, &res); /* main call */ - if (ret != 0) { /* on error exit */ + /* main body */ + ret = getaddrinfo(argv[optind], argv[optind+1], &hint, &res); + if (ret != 0) { printf("Resolution error %s\n", gai_strerror(ret)); exit(1); } - ptr = res; /* store pointer */ + ptr = res; /* init list pointer */ printf("Canonical name %s\n", ptr->ai_canonname); /* print cname */ - do { - if (ptr->ai_family == PF_INET) { + while (ptr != NULL) { /* loop on list */ + if (ptr->ai_family == PF_INET) { /* if IPv4 */ printf("IPv4 address: \n"); - addr = (struct sockaddr_in *) ptr->ai_addr; - port = ntohs(addr->sin_port); + addr = (struct sockaddr_in *) ptr->ai_addr; /* address */ + port = ntohs(addr->sin_port); /* port */ string = inet_ntop(addr->sin_family, &addr->sin_addr, buffer, sizeof(buffer)); - } else if (ptr->ai_family == PF_INET6) { + } else if (ptr->ai_family == PF_INET6) { /* if IPv6 */ printf("IPv6 address: \n"); - addr6 = (struct sockaddr_in *) ptr->ai_addr; - port = ntohs(addr6->sin6_port); + addr6 = (struct sockaddr_in *) ptr->ai_addr; /* address */ + port = ntohs(addr6->sin6_port); /* port */ string = inet_ntop(addr6->sin6_family, &addr6->sin6_addr, buffer, sizeof(buffer)); - } else { + } else { /* else is an error */ printf("Address family error\n"); exit(1); } printf("\tIndirizzo %s\n", string); printf("\tProtocollo %i\n", ptr->ai_protocol); printf("\tPorta %i\n", port); - - ptr = ptr->ai_next; - } while (ptr != NULL); + } exit(0); } /* @@ -130,7 +195,11 @@ int main(int argc, char *argv[]) void usage(void) { printf("Program mygethost: do an hostname resolution \n"); printf("Usage:\n"); - printf(" mygethost [-h] hostname service\n"); - printf(" -h print this help\n"); + printf("mygethost [-h] [-p protocol] [-t socktype] hostname service\n"); + printf(" -h print this help\n"); + printf(" -p udp,tcp select a protocol\n"); + printf(" -t dgram,stream select a socket type\n"); + printf(" -v 4,6 select IPv4 or IPv6 \n"); + printf(" -c require canonical name resolution\n"); exit(1); } -- 2.30.2