====== Zmiana adresu domenowego na IP ======
===== Tradycyjna funkcja gethostbyname =====
Najstarsze funkcje do zmiany to ''gethostbyname'' i ''gethostbyaddr''.
Funkcje są przestarzałe i powszechnie używane. Problemy z ich działaniem obrazuje poniższy kod:
#include
~~Zadanie.#~~ Przetestuj powyższy kod. Zastanów się jak uniknąć problemu, który pokazuje powyższy kod.
===== Rozszerzenia GNU =====
Kompilator GCC udostępnia wiele rozszerzeń "łatających" braki standardów [[https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html]].\\
Towarzysząca mu biblioteka [[https://www.gnu.org/software/libc/|glibc]] wprowadza między innymi funkcję ''[[https://www.gnu.org/software/libc/manual/html_node/Host-Names.html#index-gethostbyname_005fr|gethostbyname_r]]'' (funkcje ''*_r'' są reentrant, tj. można je łatwiej stosować w aplikacjach wielowątkowych [[https://en.wikipedia.org/wiki/Reentrancy_%28computing%29]]). ''gethostbyname_r'' może być używana współbieżnie.
hostent he, *resptr;
int status, retval;
char buffer[4096];
retval = gethostbyname_r("cat.put.poznan.pl", &he, buffer, sizeof(buffer), &resptr, &status);
if(retval)
error(1,0,"gethostbyname_r error: %s", hstrerror(status));
if(!resptr)
error(1,0,"empty result");
print(resptr);
===== getaddrinfo =====
Standard POSIX wprowadza funkcję ''getaddrinfo'', która pozwala na bezpieczne
tłumaczenie nazwy domenowej (lub adresu IP) z tekstu na odpowiedni format dla
funkcji sieciowych (wskaźnik na strukturę ''sockaddr''). Funkcja działa zarówno
IPv4 i IPv6.\\
''getaddrinfo'' przygotowuje wszystkie argumenty potrzebne funkcjom takim jak
''socket'', ''connect'' czy ''bind''.
Funkcja ''getaddrinfo'' sama alokuje pamięć dla wyników, stąd wyniki muszą być
zwolnione ręcznie funkcją ''freeaddrinfo''.
Standard POSIX wprowadza też m. inn. wygodną funkcję do tłumaczenia ''sockaddr*''
na tekst – funkcję ''getnameinfo''.
Składnia ''getaddrinfo'':
int getaddrinfo( // zwraca 0 (ok) lub niezerowy kod błędu (można go przerobić na tekst używając gai_strerror)
const char * ip_or_hostname, // nazwa domenowa lub adres IP
const char * port_or_service, // numer portu (np. "80") lub nazwa usługi (np. "http", ustawi port na 80)
const struct addrinfo *hints, // pozwala wybrać typ adresu, wyłączyć używanie DNS, etc.
struct addrinfo **res); // pole na wynik (jeśli puste - nic nie znaleziono)
Definicja struktury ''addrinfo'':
struct addrinfo {
int ai_flags; // pole flag, używane jeśli struktura ma być podpowiedziami dla getaddrinfo – patrz manual
int ai_family; // ai_family, ai_socktype i ai_protocol mają znaczenie identyczne jak
int ai_socktype; // w funkcji socket(). Mogą być ustawione w podpowiedziach na wybraną
int ai_protocol; // wartość lub na 0 (wtedy oznaczają wszystkie pasujące wartości)
socklen_t ai_addrlen; // ai_addr to adres o długości ai_addrlen który może być
struct sockaddr *ai_addr; // użyty w funkcji connect lub bind
char *ai_canonname; // wypełniane (tylko jeśli podano odpowiednią flagę) nazwą o którą zapytano
struct addrinfo *ai_next; // struktura addrinfo tworzy jednokierunkową linked listę, ai_next wskazuje na jej następny element
};
Składnia ''getnameinfo'':
int getnameinfo( // zwraca 0 (ok) lub niezerowy kod błędu (można go przerobić na tekst używając gai_strerror)
const struct sockaddr *addr, // adres (IPv4 lub IPv6) do przerobienia na tekst
socklen_t addrlen, // ilość bajtów powyższego adresu
//
char * host, // wskaźnik na bufor do którego zostanie wpisany adres IP (lub nazwa domenowa) jako tekst
size_t hostLen, // ilość miejsca w powyższym buforze
// (dla zmiany IP na tekst powinien wystarczyć bufor o długości NI_MAXHOST)
char * port, // wskaźnik na bufor do którego zostanie wpisany numer (lub nazwa) portu jako tekst
size_t portLen, // ilość miejsca w powyższym buforze
// (dla zmiany portu na tekst powinien wystarczyć bufor o długości NI_MAXSERV)
int flags); // pole flag, pozwalające wybrać m. inn. czy IP i port mają być tłumaczone na numery czy nazwy
Pełen opis funkcji i struktur znajdziesz na stronie manuala do getaddrinfo (''man getaddrinfo'')
lub w standardzie POSIX ([[https://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html|[1]]],
[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html|[2]]],
[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html|[3]]]).
__Uwaga:__ ''getaddrinfo'' i ''getnameinfo'' w razie sukcesu zwraca ''0'', a w
przypadku błędu zwraca jego kod. Czytelny dla człowieka komunikat powiązany z
kodem błędu można uzyskać funckją ''gai_strerror''.
Zwróć uwagę, że to odbiega od typowej konwencji POSIX.
Przykłady użycia:
#include
#include
~~Zadanie.#~~ Stwórz klienta TCP, który:
* odczyta z listy argumentów adres i numer portu
* użyje funkcji ''getaddrinfo'' z podpowiedzią żądającą protokołu TCP
* utworzy gniazdo korzystając z rodziny adresów zwróconej przez ''getaddrinfo''
* połączy się funkcją connect korzystając ze struktury sockaddr i informacji o jej długości zwróconej przez ''getaddrinfo''