[successivo] [precedente] [inizio] [fine] [indice generale]
La comunicazione tra i processi in rete è possibile se si specificano gli indirizzi dei due nodi che comunicano; come detto in precedenza essi sono costituiti da coppie IP:porta.
Quindi è fondamentale conoscere gli indirizzi IP dei nodi in cui vengono eseguiti i processi e per questo possono essere molto utili le funzioni che permettono di risalire a tali informazioni partendo dal nome delle macchine, cioè quelle che eseguono la «risoluzione dei nomi».
Tali funzioni sono definite in <netdb.h> insieme alle strutture dati che utilizzano.
La prima funzione esaminata in verità non riguarda la risoluzione dei nomi ma può essere comunque utile perché permette di conoscere il nome della macchina in cui il processo che la invoca è in esecuzione; si tratta della funzione gethostname() definita in <unistd.h> e il cui prototipo è:
int gethostname(char *nome, size_t lun) //nome è il nome che si ottiene in risposta; //lun dimensione della variabile nome. |
Ritorna 0 se non ci sono errori, altrimenti -1 (ad esempio se nome è un puntatore non valido).
Ci sono diverse funzioni utili a risolvere il nome in un indirizzo IP; iniziamo da gethostbyname() che ha questo prototipo:
struct hostent *gethostbyname(const char *nome) //trova l'indirizzo associato al nome nome. |
Ritorna il puntatore ad una struttura di tipo hostent con i dati associati al nome, oppure un puntatore nullo in caso di errore, nel qual caso la variabile esterna h_errno può valere:
HOST_NOT_FOUND o NO_DATA: dati non trovati;
TRY_AGAIN: errore temporaneo, è possibile riprovare;
mentre errno può valere:
EINTR: funzione interrota da un segnale, è possibile riprovare;
ENETDOWN: il sottosistema di rete non è attivo.
La struttura hostent è definita nel seguente modo:
struct hostent { char *h_name; // nome ufficiale dell'host char **h_aliases; // lista degli alias int h_addrtype; // tipo di indirizzo int h_length; // lunghezza dell'indirizzo char **h_addr_list; // lista degli indirizzi } #define h_addr h_addr_list[0] // primo indirizzo della lista, // serve per motivi di compatibilità |
La funzione gethostbyname() interroga un servente DNS oppure usa il contenuto del file /etc/hosts
a seconda di quanto indicato in /etc/resolv.conf
e valorizza i campi della struttura hostent in questa maniera:
h_name: nome canonico (nel caso del DNS è il nome associato ad un record «A»);
h_aliases: puntatore a un vettore di puntatori, terminato da un puntatore nullo, ciascuno dei quali punta ad una stringa contenente uno dei possibili alias del nome canonico (nel DNS sono i record «CNAME»);
h_addrtype: tipo di indirizzo restituito, AF_INET;
h_length: lunghezza dell'indirizzo;
h_addr_list: puntatore a un vettore di puntatori, terminato da un puntatore nullo, ciascuno dei quali punta a un singolo indirizzo.
La funzione gethostbyname() permette di ottenere solo indirizzi IPv4; per ottenere anche indirizzi IPv6 si utilizza gethostbyname2() che ha il seguente prototipo:
struct hostent *gethostbyname2(const char *nome, int af) //trova l'indirizzo di tipo af associato a nome. |
Questa funzione è del tutto analoga alla precedente; l'unica differenza è il parametro af da impostare come AF_INET o AF_INET6 per stabilire il tipo di indirizzi che si vuole in risposta.
Occorre ricordare infine che esistono anche le funzioni gethostbyname_r() e gethostbyname2_r() che sono le versioni rientranti delle due funzioni appena esaminate e delle quali non vengono forniti dettagli.
Per ottenere il nome di una stazione se è noto il suo indirizzo IPv4 o IPv6 si può usare la funzione gethostbyaddr() cha ha il seguente prototipo:
struct hostent *gethostbyaddr(const char *ind, int lun, int tipo) //trova il nome associato all'indirizzo ind; //lun è la dimensione dell'indirizzo (4 o 16); //tipo è il tipo di indirizzo (AF_INET o AF_INET6). |
Ritorna il puntatore a una struttura hostent in caso di successo o NULL in caso di errore; in quest'ultimo caso valgono gli stessi codici per h_errno e errno visti per la funzione gethostbyname() con in più, per errno, il valore EFAULT (ind puntatore non valido).
L'unico campo della struttura hostent da considerare è h_name contenente il nome cercato; la funziona comunque valorizza anche il primo campo di h_addr_list con l'indirizzo ind.
Si deve notare che, malgrado nel prototipo ind sia un puntatore a carattere, esso deve essere definito come struttura in_addr (o in6_addr) su cui fare il casting a puntatore a carattere.
La risoluzione dei nomi tramite un servente DNS viene effettuata solitamente con il protocollo UDP (sulla porta 53); nel caso si voglia invece ricorrere al TCP si può utilizzare la funzione sethostent() il cui prototipo è:
void sethostent(int val) //con val=1 attiva l'uso di connessioni TCP per interrogare il DNS. |
Per disattivare l'uso del TCP si usa invece endhostent() così definita:
void endhostent(void) //disattiva l'uso di connessioni TCP per interrogare il DNS. |
Nel caso sia utile utile conoscere il numero di porta associato ad un servizio di rete o viceversa si possono usare le due funzioni getservbyname() e getservbyport() con i seguenti prototipi:
struct servent *getservbyname(const char *nome, const char *proto) //restituisce la porta associata al servizio nome. struct servent *getservbyport(int porta, const char *proto) //restituisce il nome di servizio associato a porta. |
Ritornano il puntatore ad una struttura servent in caso di successo, oppure NULL se c'è errore.
In entrambe c'è l'argomento proto che indica il protocollo su cui effettuare la ricerca e che può essere udp, tcp o NULL, nel qual caso la ricerca viene fatta su un protocollo qualsiasi.
Le due funzioni si servono di quanto contenuto nel file /etc/services
per elaborare la risposta che viene restituita nella struttura servent così definita:
struct servent { char *s_name; // nome del servizio char **s_aliases; // lista di nomi ulteriori int s_port; // porta char *s_proto; // protocollo } |
Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome risoluzione_dei_nomi.html